<?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>Sat, 07 Jun 2008 06:28:01 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.5</generator>
	<language>en</language>
			<item>
		<title>The New Wave of JavaScript</title>
		<link>http://alexle.net/archives/283</link>
		<comments>http://alexle.net/archives/283#comments</comments>
		<pubDate>Fri, 06 Jun 2008 03:11:53 +0000</pubDate>
		<dc:creator>Alex le</dc:creator>
		
		<category><![CDATA[Ajax &#038; Web 2.0]]></category>

		<category><![CDATA[My Projects]]></category>

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

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

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

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

		<guid isPermaLink="false">http://alexle.net/?p=283</guid>
		<description><![CDATA[<p>I just checked out the <a href="http://280slides.com">280Slides.com</a>, a YCombinator&#8217;s funded company.  They are developing an online Slideshow/Powerpoint site (yes, another one).  The application is pretty slick and it has the Apple&#8217;s look and feel to it (both the 2 founds were from Apple).  Paul Graham used their app to create his slide at StartupSchool 2008, which at the time, took him 10 minutes to start his slides due to &#8220;technical issues&#8221;.</p>
<p>What really got me amazed is that they developed a JavaScript UI framework called Objective-J.  Apple do a lot of their apps and gadgets in Objective-C (iPhone for one), and since the guys behind 280Slides were from Apple, probably they took the concepts from Objective C and bring it over to JavaScript.  Having coded <a href="http://www.tubecaption.com">TubeCaption</a>&#8217;s caption editor, the Captionizer, from scratch, I understand how much work it takes to do something non-trivial in JavaScript.  Programming an online application is totally different than programming a simple &#8220;Ajaxy, Web2.0&#8243; page because the amount of work involved.  We have hundreds of objects potentially interact with one another and trying to compete for CPU. Without a solid foundation, the application won&#8217;t be able to bear the performance and complexity weight.</p>
<p>I&#8217;m pretty excited to hear that 280Slides is planning to open-source their framework (probably the Objective J) in the near future.  It will be a fresh idea besides the currently established frameworks such as YUI, Ext, Prototype.  </p>
<p>Increasingly I see the trend of JavaScript being used as the underlining cross-platform language to build other frameworks and programming languages on top of it.  John Resig (from jQuery) recently ported the <a href="http://processing.org/">processing visualizing language</a> to <a href="http://ejohn.org/blog/overview-of-processing/">JavaScript</a>.  His JS implementation looks AMAZING (check out the parser&#8217;s code, what a work of art) and performance-wise the library kicks major ass.  Then somebody wrote a Ruby VM in JavaScript (<a href="http://hotruby.accelart.jp/">HotRuby</a>) and Ruby code can get executed natively in the browser.  A VM written in JavaScript?  WOW! Just the thought of Rails *may* work in the browser (hopefully not IE6) makes me feel dreamy.  These stuffs are truly innovative and that&#8217;s what really push the web technologies forward. And with the new JavaScript engines that promise excellent performance (Webkit&#8217;s Squirrelfish, Mozilla&#8217;s SpiderMonkey), for sure we will even see MORE of the creative innovations.</p>
<p>PS:  don&#8217;t forget to check out <a href="http://www.tubecaption.com">www.tubecaption.com</a>&#8217;s <strong>Captionizer</strong>, the first timeline-based caption editor.</p>
]]></description>
			<content:encoded><![CDATA[<p>I just checked out the <a href="http://280slides.com">280Slides.com</a>, a YCombinator&#8217;s funded company.  They are developing an online Slideshow/Powerpoint site (yes, another one).  The application is pretty slick and it has the Apple&#8217;s look and feel to it (both the 2 founds were from Apple).  Paul Graham used their app to create his slide at StartupSchool 2008, which at the time, took him 10 minutes to start his slides due to &#8220;technical issues&#8221;.</p>
<p>What really got me amazed is that they developed a JavaScript UI framework called Objective-J.  Apple do a lot of their apps and gadgets in Objective-C (iPhone for one), and since the guys behind 280Slides were from Apple, probably they took the concepts from Objective C and bring it over to JavaScript.  Having coded <a href="http://www.tubecaption.com">TubeCaption</a>&#8217;s caption editor, the Captionizer, from scratch, I understand how much work it takes to do something non-trivial in JavaScript.  Programming an online application is totally different than programming a simple &#8220;Ajaxy, Web2.0&#8243; page because the amount of work involved.  We have hundreds of objects potentially interact with one another and trying to compete for CPU. Without a solid foundation, the application won&#8217;t be able to bear the performance and complexity weight.</p>
<p>I&#8217;m pretty excited to hear that 280Slides is planning to open-source their framework (probably the Objective J) in the near future.  It will be a fresh idea besides the currently established frameworks such as YUI, Ext, Prototype.  </p>
<p>Increasingly I see the trend of JavaScript being used as the underlining cross-platform language to build other frameworks and programming languages on top of it.  John Resig (from jQuery) recently ported the <a href="http://processing.org/">processing visualizing language</a> to <a href="http://ejohn.org/blog/overview-of-processing/">JavaScript</a>.  His JS implementation looks AMAZING (check out the parser&#8217;s code, what a work of art) and performance-wise the library kicks major ass.  Then somebody wrote a Ruby VM in JavaScript (<a href="http://hotruby.accelart.jp/">HotRuby</a>) and Ruby code can get executed natively in the browser.  A VM written in JavaScript?  WOW! Just the thought of Rails *may* work in the browser (hopefully not IE6) makes me feel dreamy.  These stuffs are truly innovative and that&#8217;s what really push the web technologies forward. And with the new JavaScript engines that promise excellent performance (Webkit&#8217;s Squirrelfish, Mozilla&#8217;s SpiderMonkey), for sure we will even see MORE of the creative innovations.</p>
<p>PS:  don&#8217;t forget to check out <a href="http://www.tubecaption.com">www.tubecaption.com</a>&#8217;s <strong>Captionizer</strong>, the first timeline-based caption editor.</p>
]]></content:encoded>
			<wfw:commentRss>http://alexle.net/archives/283/feed</wfw:commentRss>
		</item>
		<item>
		<title>Pocket full of Sunshine &#8230;</title>
		<link>http://alexle.net/archives/282</link>
		<comments>http://alexle.net/archives/282#comments</comments>
		<pubDate>Wed, 04 Jun 2008 17:01:07 +0000</pubDate>
		<dc:creator>Alex le</dc:creator>
		
		<category><![CDATA[Music]]></category>

		<category><![CDATA[My Projects]]></category>

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

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

		<category><![CDATA[natasha bedingfiled]]></category>

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

		<guid isPermaLink="false">http://alexle.net/?p=282</guid>
		<description><![CDATA[<p><object width="480" height="450" id="tubecaption_player" align="middle"><param name="allowScriptAccess" value="always" /><param name="fullscreen" value="true" /><param name="movie" value="http://www.tubecaption.com:80/flash/player.swf?v=qFsJ2pUKNVc&#038;standAlone=true&#038;vcId=13" /><param name="quality" value="high" /><param name="bgcolor" value="#000000" /><embed src="http://www.tubecaption.com:80/flash/player.swf?v=qFsJ2pUKNVc&#038;apiKey=AI39si5KfiUTw4l0qRsraFnxgk6oLv9RFs2JX38Yd1xFchQqcy0rYEsoQ7-pTgpN6DGBUb-HdfL3EK17tIUChbjORemkY4C5eg&#038;standAlone=true&#038;vcId=13" quality="high" bgcolor="#000000" width="480" height="450" name="tubecaption.com" align="middle" allowScriptAccess="always" fullscreen="true" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" /></object>
<div><a href="http://http://www.tubecaption.com/watch?v=qFsJ2pUKNVc&#038;vcId=13"><img src="http://www.tubecaption.com/flash/pf.gif"  alt="add your captions on TubeCaption.com" /></a></div>
]]></description>
			<content:encoded><![CDATA[<p><object width="480" height="450" id="tubecaption_player" align="middle"><param name="allowScriptAccess" value="always" /><param name="fullscreen" value="true" /><param name="movie" value="http://www.tubecaption.com:80/flash/player.swf?v=qFsJ2pUKNVc&#038;standAlone=true&#038;vcId=13" /><param name="quality" value="high" /><param name="bgcolor" value="#000000" /><embed src="http://www.tubecaption.com:80/flash/player.swf?v=qFsJ2pUKNVc&#038;apiKey=AI39si5KfiUTw4l0qRsraFnxgk6oLv9RFs2JX38Yd1xFchQqcy0rYEsoQ7-pTgpN6DGBUb-HdfL3EK17tIUChbjORemkY4C5eg&#038;standAlone=true&#038;vcId=13" quality="high" bgcolor="#000000" width="480" height="450" name="tubecaption.com" align="middle" allowScriptAccess="always" fullscreen="true" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" /></object>
<div><a href="http://http://www.tubecaption.com/watch?v=qFsJ2pUKNVc&#038;vcId=13"><img src="http://www.tubecaption.com/flash/pf.gif"  alt="add your captions on TubeCaption.com" /></a></div>
]]></content:encoded>
			<wfw:commentRss>http://alexle.net/archives/282/feed</wfw:commentRss>
		</item>
		<item>
		<title>ActionMailer:  Gmail SMTP, Sendmail, and spam</title>
		<link>http://alexle.net/archives/278</link>
		<comments>http://alexle.net/archives/278#comments</comments>
		<pubDate>Tue, 03 Jun 2008 19:44:44 +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[Web Technolgy]]></category>

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

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

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

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

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

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

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

		<guid isPermaLink="false">http://alexle.net/?p=278</guid>
		<description><![CDATA[<p>Recently I had to configure my VPS at <a href="http://slicehost.com">Slicehost.com</a> to send out emails for my <a href="http://www.tubecaption.com">TubeCaption </a>application. Due to the time constraint of the launch, we decided to outsource the mail delivery to Gmail SMTP server.</p>
<p><strong>Using Gmail SMTP server with ActionMailer</strong></p>
<p>When I first deployed the application, I didn&#8217;t configure sendmail correctly (I&#8217;m a total stranger to sendmail or postfix) and went ahead with Google&#8217;s SMPT server.  Since I am using Google Apps to host the mailboxes, I created an extra account specifically to use for mail delivery.  In my <strong>development.rb</strong> and <strong>production.rb</strong> file, I have ActionMailer configured as follow:</p>
<blockquote><p>ActionMailer::Base.delivery_method = :smtp<br />
ActionMailer::Base.smtp_settings = {<br />
:tls =&gt; true,<br />
:address =&gt; &#8220;smtp.gmail.com&#8221;,<br />
:port =&gt; 587,<br />
:domain =&gt; &#8220;tubecaption.com&#8221;,<br />
:authentication =&gt; :plain,<br />
:user_name =&gt; &#8220;sample-mailer-account@tubecaption.com&#8221;,<br />
:password =&gt; &#8220;the-very-secured-password&#8221;<br />
}</p></blockquote>
<p>Within my ActionMailer handler, I have a function to setup the default params as follow</p>
<blockquote><p>class Postoffice &lt; ActionMailer::Base<br />
def setup_default_params<br />
@from         = &#8220;my-email@tubecaption.com&#8221;<br />
@headers      = &#8220;Reply-to my-email@tubecaption.com&#8221;<br />
@subject      = &#8220;TubeCaption.com&#8221;<br />
@sent_on      = Time.now<br />
@content_type = &#8220;text/html&#8221;<br />
end<br />
end</p></blockquote>
<p>Then for each email, before sending, I invoke <strong>setup_default_params()</strong> to have all the params setup. The site could now sending out emails, albeit slow.  ActionMailer had to open a connection to GMail, authenticated, and then started writing the content as a stream of text.  The whole process took from 1 to 3, or even 4 seconds some time on my machines, which means the mongrel process was also stuck there waiting.   But the mailing piece worked.  However, I came to know the real issue:  all the emails were marked as SPAM or JUNK if they are sent to GMail or Yahoo.</p>
<p>I talked to a friend of mine, who has more knowledge in the emailing world.  He suggested the cause of this is because emails sent from my VPS failed the reversed DNS lookup verification.  Yahoo mail servers perform a reverse DNS look up to check my domain&#8217;s DNS records, while the SMTP server I used was from Gmail.  Hence the emails were marked as spam in Yahoo and junk in Gmail due to the DNS check mis-match.</p>
<p>So I decided that it was about time for me to configure sendmail for the box and switch ActionMailer to use sendmail instead.</p>
<p><strong>ActionMailer with local sendmail</strong></p>
<p>Truthfully speaking, I would love to get away as far as I can from configuring sendmail.  The 4th edition O&#8217;Reilly book on Sendmail is more than 1,000 pages!  I only want something that can send out emails&#8230; Luckily, there is yum.</p>
<blockquote><p># sudo yum install sendmail</p></blockquote>
<p>Now I switch my ActionMailer config back to use sendmail.  Since my sendmail is installed in the default folder, I don&#8217;t need to configure ActionMailer any further.  In <strong>production.rb</strong>, I have</p>
<blockquote><p>ActionMailer::Base.delivery_method = :sendmail</p></blockquote>
<p>ActionMailer now delivered mails using the local sendmail program.</p>
<p>Using the console, I sent out a test email to my yahoo acount.   Everything works.  Then, I received a notice from my server, telling me I have new mails at <strong>/var/spool/mail</strong>.  Great!  I checked the mail log, and saw &#8230;</p>
<blockquote><p>   &#8212;&#8211; The following addresses had permanent fatal errors &#8212;&#8211;<br />
&lt;nworld3d@yahoo.com&gt;<br />
(reason: 553 Mail from XX.XXX.XXX.XXX not allowed - 5.7.1 [BL23] Connections not accepted from IP addresses on Spamhaus XBL; see http://postmaster.yahoo.com/550-bl23.html [550])</p>
<p>&#8212;&#8211; Transcript of session follows &#8212;&#8211;<br />
&#8230; while talking to b.mx.mail.yahoo.com.:<br />
&lt;&lt;&lt; 553 Mail from XX.XXX.XXX.XXX not allowed - 5.7.1 [BL23] Connections not accepted from IP addresses on Spamhaus XBL; see http://postmaster.yahoo.com/550-bl23.html [550]<br />
&#8230; while talking to d.mx.mail.yahoo.com.:<br />
&lt;&lt;&lt; 553 Mail from XX.XXX.XXX.XXXnot allowed - 5.7.1 [BL23] Connections not accepted from IP addresses on Spamhaus XBL; see http://postmaster.yahoo.com/550-bl23.html [550]<br />
&#8230;&#8230;.<br />
&lt;&lt;&lt; 553 Mail from XX.XXX.XXX.XXX not allowed - 5.7.1 [BL23] Connections not accepted from IP addresses on Spamhaus XBL; see http://postmaster.yahoo.com/550-bl23.html [550]<br />
554 5.0.0 Service unavailable</p>
<p>&#8230;&#8230;.</p>
<p>Final-Recipient: RFC822; nworld3d@yahoo.com<br />
Action: failed<br />
Status: 5.5.0<br />
<strong>Diagnostic-Code: SMTP; 553 Mail from XX.XXX.XXX.XXX not allowed - 5.7.1 [BL23] Connections not accepted from IP addresses on Spamhaus XBL; see http://postmaster.yahoo.com/550-bl23.html [550]</strong><br />
Last-Attempt-Date: Tue, 3 Jun 2008 14:02:54 -0400</p></blockquote>
<p>OUCH!  My VPS got black-listed!  Somehow the <strong>Spamhaus XBL</strong> list decided to black list the IP address of the server.  Probably because I had port 25 opened in the firewall and somebody has taken advantage of my lack-of-linux-sysadmin-skills to start relaying spams.  CRAP! Yahoo outrightly refused any SMTP connection from my server because it was marked as a spammer-wannabe .  Good thing Yahoo included the  link to their help page and references to Spamhaus XBL.</p>
<p>I went to <a href="http://www.spamhaus.org/xbl/" target="_blank">Spamhaus website </a>and looked up my server&#8217;s IP:</p>
<p style="text-align: center;"><a href="http://alexle.net/wp-content/uploads/2008/06/spamhause-blacklisted.png"><img class="alignnone size-medium wp-image-279" title="spamhause-blacklisted" src="http://alexle.net/wp-content/uploads/2008/06/spamhause-blacklisted-300x157.png" alt="" width="300" height="157" /></a></p>
<p>The CBL (composite blocking list) was blocking my server.  I went ahead and request a removal from the list.  Afterwards, the CBL list showed</p>
<p style="text-align: center;"><a href="http://alexle.net/wp-content/uploads/2008/06/cbl-lookup.png"><img class="alignnone size-medium wp-image-281" title="cbl-lookup" src="http://alexle.net/wp-content/uploads/2008/06/cbl-lookup-300x252.png" alt="" width="300" height="252" /></a></p>
<p>A few minutes later, I checked Spamhaus and it&#8217;s not showing the IP listed anymore.  Phew!</p>
<p style="text-align: center;"><a href="http://alexle.net/wp-content/uploads/2008/06/spamhause-ok.png"><img class="alignnone size-medium wp-image-280" title="spamhause-ok" src="http://alexle.net/wp-content/uploads/2008/06/spamhause-ok-300x179.png" alt="" width="300" height="179" /></a></p>
<p>It would take a while before this list is propagated through out the internet.  At the moment, I still can&#8217;t connect to Yahoo&#8217;s SMTP server and my mails is still delivered right into Google&#8217;s Junk mailbox.  Hopefully a few hours more and my server would be good to go.</p>
<p>I don&#8217;t know if Spamhaus is my friend or foe.  I have a hard time deciding it.  I don&#8217;t know what people&#8217;s experiences with emailing services in general, but I can tell it&#8217;s a pain in the butt, and everything will only get worse from here.  I wonder what it will be like when ipv6 is used&#8230;</p>
]]></description>
			<content:encoded><![CDATA[<p>Recently I had to configure my VPS at <a href="http://slicehost.com">Slicehost.com</a> to send out emails for my <a href="http://www.tubecaption.com">TubeCaption </a>application. Due to the time constraint of the launch, we decided to outsource the mail delivery to Gmail SMTP server.</p>
<p><strong>Using Gmail SMTP server with ActionMailer</strong></p>
<p>When I first deployed the application, I didn&#8217;t configure sendmail correctly (I&#8217;m a total stranger to sendmail or postfix) and went ahead with Google&#8217;s SMPT server.  Since I am using Google Apps to host the mailboxes, I created an extra account specifically to use for mail delivery.  In my <strong>development.rb</strong> and <strong>production.rb</strong> file, I have ActionMailer configured as follow:</p>
<blockquote><p>ActionMailer::Base.delivery_method = :smtp<br />
ActionMailer::Base.smtp_settings = {<br />
:tls =&gt; true,<br />
:address =&gt; &#8220;smtp.gmail.com&#8221;,<br />
:port =&gt; 587,<br />
:domain =&gt; &#8220;tubecaption.com&#8221;,<br />
:authentication =&gt; :plain,<br />
:user_name =&gt; &#8220;sample-mailer-account@tubecaption.com&#8221;,<br />
:password =&gt; &#8220;the-very-secured-password&#8221;<br />
}</p></blockquote>
<p>Within my ActionMailer handler, I have a function to setup the default params as follow</p>
<blockquote><p>class Postoffice &lt; ActionMailer::Base<br />
def setup_default_params<br />
@from         = &#8220;my-email@tubecaption.com&#8221;<br />
@headers      = &#8220;Reply-to my-email@tubecaption.com&#8221;<br />
@subject      = &#8220;TubeCaption.com&#8221;<br />
@sent_on      = Time.now<br />
@content_type = &#8220;text/html&#8221;<br />
end<br />
end</p></blockquote>
<p>Then for each email, before sending, I invoke <strong>setup_default_params()</strong> to have all the params setup. The site could now sending out emails, albeit slow.  ActionMailer had to open a connection to GMail, authenticated, and then started writing the content as a stream of text.  The whole process took from 1 to 3, or even 4 seconds some time on my machines, which means the mongrel process was also stuck there waiting.   But the mailing piece worked.  However, I came to know the real issue:  all the emails were marked as SPAM or JUNK if they are sent to GMail or Yahoo.</p>
<p>I talked to a friend of mine, who has more knowledge in the emailing world.  He suggested the cause of this is because emails sent from my VPS failed the reversed DNS lookup verification.  Yahoo mail servers perform a reverse DNS look up to check my domain&#8217;s DNS records, while the SMTP server I used was from Gmail.  Hence the emails were marked as spam in Yahoo and junk in Gmail due to the DNS check mis-match.</p>
<p>So I decided that it was about time for me to configure sendmail for the box and switch ActionMailer to use sendmail instead.</p>
<p><strong>ActionMailer with local sendmail</strong></p>
<p>Truthfully speaking, I would love to get away as far as I can from configuring sendmail.  The 4th edition O&#8217;Reilly book on Sendmail is more than 1,000 pages!  I only want something that can send out emails&#8230; Luckily, there is yum.</p>
<blockquote><p># sudo yum install sendmail</p></blockquote>
<p>Now I switch my ActionMailer config back to use sendmail.  Since my sendmail is installed in the default folder, I don&#8217;t need to configure ActionMailer any further.  In <strong>production.rb</strong>, I have</p>
<blockquote><p>ActionMailer::Base.delivery_method = :sendmail</p></blockquote>
<p>ActionMailer now delivered mails using the local sendmail program.</p>
<p>Using the console, I sent out a test email to my yahoo acount.   Everything works.  Then, I received a notice from my server, telling me I have new mails at <strong>/var/spool/mail</strong>.  Great!  I checked the mail log, and saw &#8230;</p>
<blockquote><p>   &#8212;&#8211; The following addresses had permanent fatal errors &#8212;&#8211;<br />
&lt;nworld3d@yahoo.com&gt;<br />
(reason: 553 Mail from XX.XXX.XXX.XXX not allowed - 5.7.1 [BL23] Connections not accepted from IP addresses on Spamhaus XBL; see http://postmaster.yahoo.com/550-bl23.html [550])</p>
<p>&#8212;&#8211; Transcript of session follows &#8212;&#8211;<br />
&#8230; while talking to b.mx.mail.yahoo.com.:<br />
&lt;&lt;&lt; 553 Mail from XX.XXX.XXX.XXX not allowed - 5.7.1 [BL23] Connections not accepted from IP addresses on Spamhaus XBL; see http://postmaster.yahoo.com/550-bl23.html [550]<br />
&#8230; while talking to d.mx.mail.yahoo.com.:<br />
&lt;&lt;&lt; 553 Mail from XX.XXX.XXX.XXXnot allowed - 5.7.1 [BL23] Connections not accepted from IP addresses on Spamhaus XBL; see http://postmaster.yahoo.com/550-bl23.html [550]<br />
&#8230;&#8230;.<br />
&lt;&lt;&lt; 553 Mail from XX.XXX.XXX.XXX not allowed - 5.7.1 [BL23] Connections not accepted from IP addresses on Spamhaus XBL; see http://postmaster.yahoo.com/550-bl23.html [550]<br />
554 5.0.0 Service unavailable</p>
<p>&#8230;&#8230;.</p>
<p>Final-Recipient: RFC822; nworld3d@yahoo.com<br />
Action: failed<br />
Status: 5.5.0<br />
<strong>Diagnostic-Code: SMTP; 553 Mail from XX.XXX.XXX.XXX not allowed - 5.7.1 [BL23] Connections not accepted from IP addresses on Spamhaus XBL; see http://postmaster.yahoo.com/550-bl23.html [550]</strong><br />
Last-Attempt-Date: Tue, 3 Jun 2008 14:02:54 -0400</p></blockquote>
<p>OUCH!  My VPS got black-listed!  Somehow the <strong>Spamhaus XBL</strong> list decided to black list the IP address of the server.  Probably because I had port 25 opened in the firewall and somebody has taken advantage of my lack-of-linux-sysadmin-skills to start relaying spams.  CRAP! Yahoo outrightly refused any SMTP connection from my server because it was marked as a spammer-wannabe .  Good thing Yahoo included the  link to their help page and references to Spamhaus XBL.</p>
<p>I went to <a href="http://www.spamhaus.org/xbl/" target="_blank">Spamhaus website </a>and looked up my server&#8217;s IP:</p>
<p style="text-align: center;"><a href="http://alexle.net/wp-content/uploads/2008/06/spamhause-blacklisted.png"><img class="alignnone size-medium wp-image-279" title="spamhause-blacklisted" src="http://alexle.net/wp-content/uploads/2008/06/spamhause-blacklisted-300x157.png" alt="" width="300" height="157" /></a></p>
<p>The CBL (composite blocking list) was blocking my server.  I went ahead and request a removal from the list.  Afterwards, the CBL list showed</p>
<p style="text-align: center;"><a href="http://alexle.net/wp-content/uploads/2008/06/cbl-lookup.png"><img class="alignnone size-medium wp-image-281" title="cbl-lookup" src="http://alexle.net/wp-content/uploads/2008/06/cbl-lookup-300x252.png" alt="" width="300" height="252" /></a></p>
<p>A few minutes later, I checked Spamhaus and it&#8217;s not showing the IP listed anymore.  Phew!</p>
<p style="text-align: center;"><a href="http://alexle.net/wp-content/uploads/2008/06/spamhause-ok.png"><img class="alignnone size-medium wp-image-280" title="spamhause-ok" src="http://alexle.net/wp-content/uploads/2008/06/spamhause-ok-300x179.png" alt="" width="300" height="179" /></a></p>
<p>It would take a while before this list is propagated through out the internet.  At the moment, I still can&#8217;t connect to Yahoo&#8217;s SMTP server and my mails is still delivered right into Google&#8217;s Junk mailbox.  Hopefully a few hours more and my server would be good to go.</p>
<p>I don&#8217;t know if Spamhaus is my friend or foe.  I have a hard time deciding it.  I don&#8217;t know what people&#8217;s experiences with emailing services in general, but I can tell it&#8217;s a pain in the butt, and everything will only get worse from here.  I wonder what it will be like when ipv6 is used&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://alexle.net/archives/278/feed</wfw:commentRss>
		</item>
		<item>
		<title>Grrr&#8230; cache_fu caught me off-guard</title>
		<link>http://alexle.net/archives/276</link>
		<comments>http://alexle.net/archives/276#comments</comments>
		<pubDate>Sun, 01 Jun 2008 06:37:24 +0000</pubDate>
		<dc:creator>Alex le</dc:creator>
		
		<category><![CDATA[Random Walk]]></category>

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

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

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

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

		<guid isPermaLink="false">http://alexle.net/?p=276</guid>
		<description><![CDATA[<p>I was implementing cache_fu for my upcoming application based on YouTube (will be premiered very soon here on my blog).  I wanted to cache certain calls to the YouTube API to reduce the latency and the time mongrels got stuck waiting for the response.  The first candidate to get cached was the &#8220;Top Rated Video&#8221; from YouTube.  Since this section is a part of the homepage, I used fragment caching for it.  Everything went fine, Memcached just ran so beautifully and the speed gain was exceptional.  I added the :ttl option to the cache command to expire the contents, then suddenly nothing worked.  Rails kept on whining for the cache helper call:</p>
<blockquote>
<pre><code>wrong number of arguments (2 for 1)</code></pre>
</blockquote>
<p>I checked and double-checked cache_fu source, and the fragment_cache.rb file in particular.  I saw cache_fu extending the fragment cache helper with an extra hash argument to support the :ttl option.  Why the hell I could not use it in my view?</p>
<p>It turned out that the <strong>fragment_cache</strong> overwrite in <strong>cache_fu</strong> was not called automatically.  I had to manually added the call in <strong>environment.rb</strong> file to invoke the setup.   Strange!  It took me a while to figure out since I traced all source files in cache_fu to find the bug.  I have to admit, cache_fu (previously known as acts_as_cached) has some kick-ass Ruby code written.  I still need to learn a lot more about Ruby to get to that level of code craftsmanship.</p>
<p>To fix this issue, include this one line in your <strong>environment.rb</strong> file</p>
<blockquote><p>ActsAsCached::FragmentCache.setup!</p></blockquote>
<p>That will ensure the cache helper to have the :ttl option.</p>
]]></description>
			<content:encoded><![CDATA[<p>I was implementing cache_fu for my upcoming application based on YouTube (will be premiered very soon here on my blog).  I wanted to cache certain calls to the YouTube API to reduce the latency and the time mongrels got stuck waiting for the response.  The first candidate to get cached was the &#8220;Top Rated Video&#8221; from YouTube.  Since this section is a part of the homepage, I used fragment caching for it.  Everything went fine, Memcached just ran so beautifully and the speed gain was exceptional.  I added the :ttl option to the cache command to expire the contents, then suddenly nothing worked.  Rails kept on whining for the cache helper call:</p>
<blockquote>
<pre><code>wrong number of arguments (2 for 1)</code></pre>
</blockquote>
<p>I checked and double-checked cache_fu source, and the fragment_cache.rb file in particular.  I saw cache_fu extending the fragment cache helper with an extra hash argument to support the :ttl option.  Why the hell I could not use it in my view?</p>
<p>It turned out that the <strong>fragment_cache</strong> overwrite in <strong>cache_fu</strong> was not called automatically.  I had to manually added the call in <strong>environment.rb</strong> file to invoke the setup.   Strange!  It took me a while to figure out since I traced all source files in cache_fu to find the bug.  I have to admit, cache_fu (previously known as acts_as_cached) has some kick-ass Ruby code written.  I still need to learn a lot more about Ruby to get to that level of code craftsmanship.</p>
<p>To fix this issue, include this one line in your <strong>environment.rb</strong> file</p>
<blockquote><p>ActsAsCached::FragmentCache.setup!</p></blockquote>
<p>That will ensure the cache helper to have the :ttl option.</p>
]]></content:encoded>
			<wfw:commentRss>http://alexle.net/archives/276/feed</wfw:commentRss>
		</item>
		<item>
		<title>Installing Memcached from Source on CentOS 5</title>
		<link>http://alexle.net/archives/275</link>
		<comments>http://alexle.net/archives/275#comments</comments>
		<pubDate>Fri, 30 May 2008 04:33:15 +0000</pubDate>
		<dc:creator>Alex le</dc:creator>
		
		<category><![CDATA[Server]]></category>

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

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

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

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

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

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

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

		<guid isPermaLink="false">http://alexle.net/?p=275</guid>
		<description><![CDATA[<p>This is a quick summary for this process so that I can refer to it later on, and hopefully someone will find it useful as well.</p>
<p>Memcached requires libevent to handle its network IO stuff.  The bundled libevent in the standard yum repository is old so it&#8217;s pretty useless.  The newer versions memcached runs on newer libevent library so I ended up compiling libevent and memcached from the latest stable sources.  I&#8217;m using libevent-1.4.4-stable and memcached-1.2.5.</p>
<p>First off, uninstall the libevent that yum may have installed on your machine</p>
<blockquote><p><strong># sudo yum remove libevent</strong></p></blockquote>
<p>Download the sources for libevent and memcached , unzip( # gunzip *.gz ), untar (# tar -xvf *.tar), CD to the libevent folder.  We will compile the libevent first.</p>
<blockquote><p><strong># ./configure  &#8211;prefix=/usr/local</strong></p>
<p><strong># make</strong></p>
<p><strong># make install</strong></p></blockquote>
<p>Basically we are telling libevent to install itself under /usr/local/lib/.  When we compile memcached, we need to point it to the correct location as well.  Once libevent is done installing (it&#8217;s really quick), we can move on and complie memcached.</p>
<p>CD to the un-tar memcached folder,</p>
<blockquote><p><strong># ./configure &#8211;with-lib-event=/usr/local/</strong></p>
<p><strong># make</strong></p>
<p><strong># make install</strong></p></blockquote>
<p>After memcached is installed, you can try</p>
<blockquote><p><strong># memcached</strong></p></blockquote>
<p>In my situation, I ran into an error</p>
<blockquote><p><strong>error while loading shared libraries: libevent-1.4.so.2: cannot open shared object file: No such file or directory</strong></p></blockquote>
<p>It turned out that the new libevent get installed, it doesn&#8217;t &#8220;register&#8221; the actual library file (similar to DLL on Windows) with the system.  When Memcached runs, it tries to look for the libevent-1.4.so.2 file but since libevent is still playing hide and seek somewhere, memcached cries.</p>
<p>To fix this, we need to manually load the libevent library file into the system via the <strong>ld </strong>configuration.  From the man page of <strong>ld</strong>:</p>
<blockquote><p><em>ld combines a number of object and archive files, relocates their data and ties  up  symbol  references. Usually the last step in compiling a program is to run ld.</em></p></blockquote>
<p>I like to think <strong>ld</strong> as the <strong>regsrv32 </strong>used to register DLL&#8217;s on Windows.  Now to fix up the reference to the  libevent so file, we need to create a file under <strong>/etc/ld.so.conf.d/</strong></p>
<blockquote><p><strong># vi /etc/ld.so.conf.d/libevent-i386.conf</strong></p></blockquote>
<p>then enter</p>
<blockquote><p><strong>/usr/local/lib/</strong></p></blockquote>
<p>Write and quit (<strong>:wq!</strong>)</p>
<p>The path in the <strong>libevent-i386.conf</strong> is the path where the actual .so files are located at.  We set this path when we run the <strong>./configure &#8211;prefix=/usr/local/</strong> during the libevent compilation.  Reloading the ld configuration with</p>
<p><strong># ldconfig</strong></p>
<p>now, you can start memcached in verbose mode (-vv) for testing</p>
<p><strong># memcached -vv</strong></p>
<p>If you see something like ..</p>
<blockquote><p>slab class   1: chunk size    104 perslab 10082<br />
slab class   2: chunk size    136 perslab  7710<br />
slab class   3: chunk size    176 perslab  5957<br />
slab class   4: chunk size    224 perslab  4681<br />
slab class   5: chunk size    280 perslab  3744</p>
<p>&#8230;.</p>
<p>slab class  37: chunk size 367192 perslab     2<br />
slab class  38: chunk size 458992 perslab     2<br />
&lt;6 server listening<br />
&lt;7 send buffer was 126976, now 268435456<br />
&lt;7 server listening (udp)</p></blockquote>
<p>Congratulations!  Memcached is up and running!</p>
<p>PS:  I&#8217;m renting the VPS from <a href="http://www.slicehost.com" target="_blank">www.slicehost.com</a> and so far my experience with them ( 1.5 months) is excellent.</p>
]]></description>
			<content:encoded><![CDATA[<p>This is a quick summary for this process so that I can refer to it later on, and hopefully someone will find it useful as well.</p>
<p>Memcached requires libevent to handle its network IO stuff.  The bundled libevent in the standard yum repository is old so it&#8217;s pretty useless.  The newer versions memcached runs on newer libevent library so I ended up compiling libevent and memcached from the latest stable sources.  I&#8217;m using libevent-1.4.4-stable and memcached-1.2.5.</p>
<p>First off, uninstall the libevent that yum may have installed on your machine</p>
<blockquote><p><strong># sudo yum remove libevent</strong></p></blockquote>
<p>Download the sources for libevent and memcached , unzip( # gunzip *.gz ), untar (# tar -xvf *.tar), CD to the libevent folder.  We will compile the libevent first.</p>
<blockquote><p><strong># ./configure  &#8211;prefix=/usr/local</strong></p>
<p><strong># make</strong></p>
<p><strong># make install</strong></p></blockquote>
<p>Basically we are telling libevent to install itself under /usr/local/lib/.  When we compile memcached, we need to point it to the correct location as well.  Once libevent is done installing (it&#8217;s really quick), we can move on and complie memcached.</p>
<p>CD to the un-tar memcached folder,</p>
<blockquote><p><strong># ./configure &#8211;with-lib-event=/usr/local/</strong></p>
<p><strong># make</strong></p>
<p><strong># make install</strong></p></blockquote>
<p>After memcached is installed, you can try</p>
<blockquote><p><strong># memcached</strong></p></blockquote>
<p>In my situation, I ran into an error</p>
<blockquote><p><strong>error while loading shared libraries: libevent-1.4.so.2: cannot open shared object file: No such file or directory</strong></p></blockquote>
<p>It turned out that the new libevent get installed, it doesn&#8217;t &#8220;register&#8221; the actual library file (similar to DLL on Windows) with the system.  When Memcached runs, it tries to look for the libevent-1.4.so.2 file but since libevent is still playing hide and seek somewhere, memcached cries.</p>
<p>To fix this, we need to manually load the libevent library file into the system via the <strong>ld </strong>configuration.  From the man page of <strong>ld</strong>:</p>
<blockquote><p><em>ld combines a number of object and archive files, relocates their data and ties  up  symbol  references. Usually the last step in compiling a program is to run ld.</em></p></blockquote>
<p>I like to think <strong>ld</strong> as the <strong>regsrv32 </strong>used to register DLL&#8217;s on Windows.  Now to fix up the reference to the  libevent so file, we need to create a file under <strong>/etc/ld.so.conf.d/</strong></p>
<blockquote><p><strong># vi /etc/ld.so.conf.d/libevent-i386.conf</strong></p></blockquote>
<p>then enter</p>
<blockquote><p><strong>/usr/local/lib/</strong></p></blockquote>
<p>Write and quit (<strong>:wq!</strong>)</p>
<p>The path in the <strong>libevent-i386.conf</strong> is the path where the actual .so files are located at.  We set this path when we run the <strong>./configure &#8211;prefix=/usr/local/</strong> during the libevent compilation.  Reloading the ld configuration with</p>
<p><strong># ldconfig</strong></p>
<p>now, you can start memcached in verbose mode (-vv) for testing</p>
<p><strong># memcached -vv</strong></p>
<p>If you see something like ..</p>
<blockquote><p>slab class   1: chunk size    104 perslab 10082<br />
slab class   2: chunk size    136 perslab  7710<br />
slab class   3: chunk size    176 perslab  5957<br />
slab class   4: chunk size    224 perslab  4681<br />
slab class   5: chunk size    280 perslab  3744</p>
<p>&#8230;.</p>
<p>slab class  37: chunk size 367192 perslab     2<br />
slab class  38: chunk size 458992 perslab     2<br />
&lt;6 server listening<br />
&lt;7 send buffer was 126976, now 268435456<br />
&lt;7 server listening (udp)</p></blockquote>
<p>Congratulations!  Memcached is up and running!</p>
<p>PS:  I&#8217;m renting the VPS from <a href="http://www.slicehost.com" target="_blank">www.slicehost.com</a> and so far my experience with them ( 1.5 months) is excellent.</p>
]]></content:encoded>
			<wfw:commentRss>http://alexle.net/archives/275/feed</wfw:commentRss>
		</item>
		<item>
		<title>7m7y and a small announcement</title>
		<link>http://alexle.net/archives/274</link>
		<comments>http://alexle.net/archives/274#comments</comments>
		<pubDate>Mon, 26 May 2008 15:44:08 +0000</pubDate>
		<dc:creator>Alex le</dc:creator>
		
		<category><![CDATA[money]]></category>

		<category><![CDATA[millionaire money]]></category>

		<guid isPermaLink="false">http://alexle.net/?p=274</guid>
		<description><![CDATA[<p>Recently I&#8217;ve come to know about Adrian at 7Million7Years.  He&#8217;s a successful entrepreneur with lots of experience in running businesses and investments.  Adrian decided to share his success and his wisdom with the next 7 &#8220;apprentices.&#8221;  I applied on the first day and today, I&#8217;ve got featured as one of the applicants on his 7m7y site.</p>
<p>The first task I have to do is to get more traffic to my so-called &#8220;profile&#8221; page.  I intend to leverage the traffic to my blog and open a pop-under to the page.  Yes, I know pop-under is annoying, but I only have the pop-up until June 2nd (in a week).</p>
<p>Visit my <a href="http://7m7y.com/2008/05/26/meet-alex/" target="_blank">Featured Profile Page at 7M7Y</a></p>
<p>In return, if I get selected to be one of the 7 millionaires in training, I will share more of my &#8220;million&#8221; journey to everyone.</p>
]]></description>
			<content:encoded><![CDATA[<p>Recently I&#8217;ve come to know about Adrian at 7Million7Years.  He&#8217;s a successful entrepreneur with lots of experience in running businesses and investments.  Adrian decided to share his success and his wisdom with the next 7 &#8220;apprentices.&#8221;  I applied on the first day and today, I&#8217;ve got featured as one of the applicants on his 7m7y site.</p>
<p>The first task I have to do is to get more traffic to my so-called &#8220;profile&#8221; page.  I intend to leverage the traffic to my blog and open a pop-under to the page.  Yes, I know pop-under is annoying, but I only have the pop-up until June 2nd (in a week).</p>
<p>Visit my <a href="http://7m7y.com/2008/05/26/meet-alex/" target="_blank">Featured Profile Page at 7M7Y</a></p>
<p>In return, if I get selected to be one of the 7 millionaires in training, I will share more of my &#8220;million&#8221; journey to everyone.</p>
]]></content:encoded>
			<wfw:commentRss>http://alexle.net/archives/274/feed</wfw:commentRss>
		</item>
		<item>
		<title>Comcast: The new devil</title>
		<link>http://alexle.net/archives/273</link>
		<comments>http://alexle.net/archives/273#comments</comments>
		<pubDate>Sun, 18 May 2008 19:38:12 +0000</pubDate>
		<dc:creator>Alex Le</dc:creator>
		
		<category><![CDATA[Random Walk]]></category>

		<guid isPermaLink="false">http://alexle.net/?p=273</guid>
		<description><![CDATA[<p>It&#8217;s time to say NO to monopoly and for Net Neutrality to be passed as a law.</p>
<p>It&#8217;s not Comcastic as you all claim. It&#8217;s ComCraptic. My experiences<br />
with Comcast has got from worse to worser, and now I am a very unhappy<br />
customer. Comcast is in fact using dirty and shady tactics, often<br />
disguised as to help &#8220;preserve the speed for its users&#8221;, to severely<br />
throttle services that are not in its interest to run on the network.<br />
YouTube doesn&#8217;t even want to stream sometime, meanwhile Hulu.com (a new<br />
TV-show site) is streaming Hi-Def videos just fine and it is extremely<br />
fast (because Hulu is not that big yet and so it&#8217;s not on the black<br />
slow-list). Netflix Watchnow is now extremely slow and almost<br />
unbearable. I watched a 24-min animation episode and it took 20 minutes<br />
to download the video! I always have DUMeter installed so I constantly<br />
monitored my download/upload rate. Before, for Netflix, I was streaming<br />
at 500KBps - it was almost instant to begin watching the instant<br />
videos. This is how the new &#8220;internet experience&#8221; should be. I was a<br />
very happy Comcast customer.</p>
<p>I started to read on Slashdot about<br />
Comcast trying to slow down BitTorrent and other traffic. NO! All<br />
traffic on the Web should be considered EQUAL. Why are we trying so<br />
hard to erase racial discrimination while Comcast is trying its best to<br />
discriminate and destroy the foundation of &#8220;free internet&#8221; ? And NOBODY<br />
right now can do a thing to change this evil Comcrap piece of @#$? What<br />
would happen if Comcast begins to extort money from Netflix, YouTube,<br />
Hulu, or even Amazon, to allow users to use these excellent services?<br />
That would be the end of the free internet.</p>
<p>After a &#8220;service outage&#8221; in my area, the speed of Comcast degraded<br />
worst than anything. YouTube streaming speed is out right ridiculous,<br />
if not pathetic. Netflix streaming speed degraded from 500KBps to<br />
300KBps, and now, as I&#8217;m typing this, it&#8217;s only downloading at much<br />
less than 100KBps. It took 20 minutes to half an hour for anything to<br />
work. This is pathetic. And Comcast did NOT disclose anything about<br />
their practices, not until people started to discover concrete proofs.</p>
<p><a href="http://alexle.net/wp-content/uploads/2008/05/comcast-network.jpg"><img class="aligncenter size-full wp-image-272" title="comcast-network" src="http://alexle.net/wp-content/uploads/2008/05/comcast-network.jpg" alt="" width="500" height="655" /></a></p>
<p>(<a href="http://netflixcommunity.ning.com/forum/topic/show?id=1993323%3ATopic%3A7612" target="_blank">http://netflixcommunity.ning.com</a>)</p>
<p>I found this diagram while searching on Comcast and its shady and<br />
disrespects of the customer practice. I don&#8217;t think any explanation is<br />
needed.</p>
<p>What kills the internet? Not spam, not phishing, not videos<br />
streaming, not the data tsunami. It is the unfair practices from ISP<br />
that slow down the evolution of the internet. Comcast is playing its<br />
monopoly hand to dominate places where users don&#8217;t have an alternative.<br />
And yet, they have all the power to fudge, deny, or change the TOS for<br />
their own legal and financial benefits. I would pay double for my<br />
internet connection if I have any choice other than Comcrap. That&#8217;s<br />
right, I would pay $118 a month for any ISP that works and treats their<br />
customers honestly.</p>
<p>In the US, everything is built on Trust, and Credit. Hence we have<br />
credit history, credit cards, personal loans, and mortgages. If<br />
corporations like Comcast are abusing and destroying this circle of<br />
trust and credibility, society as a whole, will be mubh better off<br />
without them.</p>
<p>Comcast, I sincerely wish you would go to hell for your practices.<br />
Meanwhile, you will go to sleep better if you treat your customers with<br />
dignity.</p>
]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s time to say NO to monopoly and for Net Neutrality to be passed as a law.</p>
<p>It&#8217;s not Comcastic as you all claim. It&#8217;s ComCraptic. My experiences<br />
with Comcast has got from worse to worser, and now I am a very unhappy<br />
customer. Comcast is in fact using dirty and shady tactics, often<br />
disguised as to help &#8220;preserve the speed for its users&#8221;, to severely<br />
throttle services that are not in its interest to run on the network.<br />
YouTube doesn&#8217;t even want to stream sometime, meanwhile Hulu.com (a new<br />
TV-show site) is streaming Hi-Def videos just fine and it is extremely<br />
fast (because Hulu is not that big yet and so it&#8217;s not on the black<br />
slow-list). Netflix Watchnow is now extremely slow and almost<br />
unbearable. I watched a 24-min animation episode and it took 20 minutes<br />
to download the video! I always have DUMeter installed so I constantly<br />
monitored my download/upload rate. Before, for Netflix, I was streaming<br />
at 500KBps - it was almost instant to begin watching the instant<br />
videos. This is how the new &#8220;internet experience&#8221; should be. I was a<br />
very happy Comcast customer.</p>
<p>I started to read on Slashdot about<br />
Comcast trying to slow down BitTorrent and other traffic. NO! All<br />
traffic on the Web should be considered EQUAL. Why are we trying so<br />
hard to erase racial discrimination while Comcast is trying its best to<br />
discriminate and destroy the foundation of &#8220;free internet&#8221; ? And NOBODY<br />
right now can do a thing to change this evil Comcrap piece of @#$? What<br />
would happen if Comcast begins to extort money from Netflix, YouTube,<br />
Hulu, or even Amazon, to allow users to use these excellent services?<br />
That would be the end of the free internet.</p>
<p>After a &#8220;service outage&#8221; in my area, the speed of Comcast degraded<br />
worst than anything. YouTube streaming speed is out right ridiculous,<br />
if not pathetic. Netflix streaming speed degraded from 500KBps to<br />
300KBps, and now, as I&#8217;m typing this, it&#8217;s only downloading at much<br />
less than 100KBps. It took 20 minutes to half an hour for anything to<br />
work. This is pathetic. And Comcast did NOT disclose anything about<br />
their practices, not until people started to discover concrete proofs.</p>
<p><a href="http://alexle.net/wp-content/uploads/2008/05/comcast-network.jpg"><img class="aligncenter size-full wp-image-272" title="comcast-network" src="http://alexle.net/wp-content/uploads/2008/05/comcast-network.jpg" alt="" width="500" height="655" /></a></p>
<p>(<a href="http://netflixcommunity.ning.com/forum/topic/show?id=1993323%3ATopic%3A7612" target="_blank">http://netflixcommunity.ning.com</a>)</p>
<p>I found this diagram while searching on Comcast and its shady and<br />
disrespects of the customer practice. I don&#8217;t think any explanation is<br />
needed.</p>
<p>What kills the internet? Not spam, not phishing, not videos<br />
streaming, not the data tsunami. It is the unfair practices from ISP<br />
that slow down the evolution of the internet. Comcast is playing its<br />
monopoly hand to dominate places where users don&#8217;t have an alternative.<br />
And yet, they have all the power to fudge, deny, or change the TOS for<br />
their own legal and financial benefits. I would pay double for my<br />
internet connection if I have any choice other than Comcrap. That&#8217;s<br />
right, I would pay $118 a month for any ISP that works and treats their<br />
customers honestly.</p>
<p>In the US, everything is built on Trust, and Credit. Hence we have<br />
credit history, credit cards, personal loans, and mortgages. If<br />
corporations like Comcast are abusing and destroying this circle of<br />
trust and credibility, society as a whole, will be mubh better off<br />
without them.</p>
<p>Comcast, I sincerely wish you would go to hell for your practices.<br />
Meanwhile, you will go to sleep better if you treat your customers with<br />
dignity.</p>
]]></content:encoded>
			<wfw:commentRss>http://alexle.net/archives/273/feed</wfw:commentRss>
		</item>
		<item>
		<title>Multiple Capistrano (or gem) Versions on Windows</title>
		<link>http://alexle.net/archives/268</link>
		<comments>http://alexle.net/archives/268#comments</comments>
		<pubDate>Tue, 06 May 2008 16:18:22 +0000</pubDate>
		<dc:creator>Alex le</dc:creator>
		
		<category><![CDATA[My Projects]]></category>

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

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

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

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

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

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

		<guid isPermaLink="false">http://alexle.net/?p=268</guid>
		<description><![CDATA[<p>If you do &#8220;gem install capistrano&#8221;, the gem package manager will go fetch the latest gem version of capistrano, currently 2.3.0 and installed in the gem repository.  In case you want to have multiple version s of capistrano running, here&#8217;s how to do it.</p>
<p>To install older gem version of Capistrano<br />
<strong>gem install &#8211;version 1.4.2 capistrano</strong><br />
(1.4.2 is the latest one in the 1.x branch before the release of 2.0)</p>
<p>To run specifically the 1.4.2 version, use<br />
<strong>cap _1.4.2_ *your_tasks_here*</strong></p>
<p><strong>Shortcut</strong><br />
To reduce the typing, you can make an alias in your .bash_profile on Linux to run the 1.4.2 version as cap1 (cap 2.x.x is still running as cap) using</p>
<p><strong># add this line to .bash_profile<br />
alias cap1=&#8221;cap _1.4.2_&#8221;</strong></p>
<p>Afterwards, reload the profile with </p>
<p><strong>$ source .bash_profile</p>
<p></strong><br />
Since I am on Windows, what I did was creating a batch file called &#8220;<strong>cap1.bat</strong>&#8221; and saved it within my system&#8217;s PATH environment.  For simplicity&#8217;s sake, I save the <strong>cap1.bat</strong> file inside my <strong>C:\Windows\System32</strong> folder</p>
<p><strong>@echo off<br />
cap _1.4.2_ %*</strong></p>
<p>The special wildcard %* will be replaced with your command-line arguments, saving you the typing.</p>
<p>To read more about the Capistrano 1.4.2 version, <a href="http://weblog.jamisbuck.org/2008/4/30/maintenance-releases-capistrano-net-ssh">check out Jamis&#8217;s post here</a>.</p>
]]></description>
			<content:encoded><![CDATA[<p>If you do &#8220;gem install capistrano&#8221;, the gem package manager will go fetch the latest gem version of capistrano, currently 2.3.0 and installed in the gem repository.  In case you want to have multiple version s of capistrano running, here&#8217;s how to do it.</p>
<p>To install older gem version of Capistrano<br />
<strong>gem install &#8211;version 1.4.2 capistrano</strong><br />
(1.4.2 is the latest one in the 1.x branch before the release of 2.0)</p>
<p>To run specifically the 1.4.2 version, use<br />
<strong>cap _1.4.2_ *your_tasks_here*</strong></p>
<p><strong>Shortcut</strong><br />
To reduce the typing, you can make an alias in your .bash_profile on Linux to run the 1.4.2 version as cap1 (cap 2.x.x is still running as cap) using</p>
<p><strong># add this line to .bash_profile<br />
alias cap1=&#8221;cap _1.4.2_&#8221;</strong></p>
<p>Afterwards, reload the profile with </p>
<p><strong>$ source .bash_profile</p>
<p></strong><br />
Since I am on Windows, what I did was creating a batch file called &#8220;<strong>cap1.bat</strong>&#8221; and saved it within my system&#8217;s PATH environment.  For simplicity&#8217;s sake, I save the <strong>cap1.bat</strong> file inside my <strong>C:\Windows\System32</strong> folder</p>
<p><strong>@echo off<br />
cap _1.4.2_ %*</strong></p>
<p>The special wildcard %* will be replaced with your command-line arguments, saving you the typing.</p>
<p>To read more about the Capistrano 1.4.2 version, <a href="http://weblog.jamisbuck.org/2008/4/30/maintenance-releases-capistrano-net-ssh">check out Jamis&#8217;s post here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://alexle.net/archives/268/feed</wfw:commentRss>
		</item>
		<item>
		<title>Ruby 1.8.6 and Gem 1.1.1 error:  gem_original_require for zlib</title>
		<link>http://alexle.net/archives/266</link>
		<comments>http://alexle.net/archives/266#comments</comments>
		<pubDate>Tue, 06 May 2008 06:37:48 +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[Web Technolgy]]></category>

		<guid isPermaLink="false">http://alexle.net/?p=266</guid>
		<description><![CDATA[<p>I&#8217;m in the process of installing Ruby on Rails on a VPS running CentOS 5.1 and run into an issue with gem complaining for the missing zlib library.  What happened was that I first used &#8220;sudo yum install ruby&#8221; to install the ruby runtime.  However, the pre-packaged ruby in the Yum repository was older, 1.8.5.  I only found out about this when I tried to run the mongrel_cluster to set up the mongrel instances.  Mongrel was complaining about the older version of Ruby and the need for the fcgi fix.  I decided to uninstall the yum ruby package and compile the newer version of Ruby from the source.</p>
<p>I compiled and installed Ruby 1.8.6 from the tar ball source first (./configure, make, make install), then I removed the pre-installed package using &#8220;sudo yum remove ruby&#8221; and removed all the dependencies with it.  Next I installed gem 1.1.1 from the source (ruby setup.rb).  I proceeded to install rails 2.0.2 again (&#8221;sudo gem install rails -y&#8221;).  Bam, gem started to complain:</p>
<pre name="code">
/usr/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in
`gem_original_require': no such file to load -- zlib (LoadError)
</pre>
<p>Not good!</p>
<p>I did some research and it turned out that my CentOS 5.1 VPS is a barebone box, it did have the extra development libraries installed.  Hence when I compiled Ruby from source, make did not compile the zlib extension because I did not have the zlib-devel package installed.  </p>
<p>After installing zlib-devel package through yum (&#8221;sudo yum install zlib-devel&#8221;), I cd&#8217;ed into my Ruby source folder and into the ext/zlib folder (in my case, ruby-1.8.6-p114/ext/zlib/).  Then I proceeded to install the zlib library (&#8221;ruby extconf.rb&#8221;, &#8220;make&#8221;, &#8220;make install&#8221;).  Afterwards, gem was working fine again!  Yay!</p>
]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m in the process of installing Ruby on Rails on a VPS running CentOS 5.1 and run into an issue with gem complaining for the missing zlib library.  What happened was that I first used &#8220;sudo yum install ruby&#8221; to install the ruby runtime.  However, the pre-packaged ruby in the Yum repository was older, 1.8.5.  I only found out about this when I tried to run the mongrel_cluster to set up the mongrel instances.  Mongrel was complaining about the older version of Ruby and the need for the fcgi fix.  I decided to uninstall the yum ruby package and compile the newer version of Ruby from the source.</p>
<p>I compiled and installed Ruby 1.8.6 from the tar ball source first (./configure, make, make install), then I removed the pre-installed package using &#8220;sudo yum remove ruby&#8221; and removed all the dependencies with it.  Next I installed gem 1.1.1 from the source (ruby setup.rb).  I proceeded to install rails 2.0.2 again (&#8221;sudo gem install rails -y&#8221;).  Bam, gem started to complain:</p>
<pre name="code">
/usr/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in
`gem_original_require': no such file to load -- zlib (LoadError)
</pre>
<p>Not good!</p>
<p>I did some research and it turned out that my CentOS 5.1 VPS is a barebone box, it did have the extra development libraries installed.  Hence when I compiled Ruby from source, make did not compile the zlib extension because I did not have the zlib-devel package installed.  </p>
<p>After installing zlib-devel package through yum (&#8221;sudo yum install zlib-devel&#8221;), I cd&#8217;ed into my Ruby source folder and into the ext/zlib folder (in my case, ruby-1.8.6-p114/ext/zlib/).  Then I proceeded to install the zlib library (&#8221;ruby extconf.rb&#8221;, &#8220;make&#8221;, &#8220;make install&#8221;).  Afterwards, gem was working fine again!  Yay!</p>
]]></content:encoded>
			<wfw:commentRss>http://alexle.net/archives/266/feed</wfw:commentRss>
		</item>
		<item>
		<title>18 JavaScript Power-Tips to help you write better and nicer JavaScript</title>
		<link>http://alexle.net/archives/260</link>
		<comments>http://alexle.net/archives/260#comments</comments>
		<pubDate>Mon, 05 May 2008 03:06:32 +0000</pubDate>
		<dc:creator>Alex le</dc:creator>
		
		<category><![CDATA[Ajax &#038; Web 2.0]]></category>

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

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

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

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

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

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

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

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

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

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

		<guid isPermaLink="false">http://alexle.net/?p=260</guid>
		<description><![CDATA[<p>I&#8217;ve been working extensively with JavaScript for the past few weeks, developing an all-Javascript application (the code base is exceeding 2000 lines of JavaScript already).  Since the application needs to scale well with a large amount of dynamically generated elements, I have discovered, learend, and used quite a few shortcuts to boost the speed, minimize memory usage with mem-leak checks, and reduce file-size in general while still maintain the readability of the code.  </p>
<p>This article is mainly about the nuggets that I extract out from my experience.  I learned a few things from reading the source of <a href="http://www.prototypejs.org">PrototypeJS</a> and <a href="http://script.aculo.us/">Scriptaculous</a>, while I learned other things (ideas, concepts) from different languages such as Ruby (famous for one-liners).  I have to admit, nothing beats reading other people&#8217;s source code.  Prototype is extremely well-written and there are tons of programming gems that one can learn from.</p>
<p>A few tricks are possible only in JavaScript because it is NOT Java, or C#, or C, and it is extremely powerful and flexible.  With the Prototype cool-aid, Object-Oriented JavaScript is not only possible, but easy, standardized, and straight-forward to implement </p>
<p><b>Tip 0:  Use a JavaScript framework</b><br />
Pick a framework and use it.  Any framework is *much* better than no framework at all.  Different browser behaves differently and the framework will help smooth out those wrinkles.  You are simply insane if you are not using one.</p>
<p>Our menu comes with several choices:  so it&#8217;s a matter of personal preference.  The learning curve will a bit steep as you will have to Google alot for the API&#8217;s, but once you are familiar and comfortable, you will become a much better scripter.</p>
<ul>
<li>Prototype:  Easy to use.  One of the first that popularized the idea of frameworks.  Lowest learning curve with virtually NO dependencies (1 file, ~ 130Kb)</li>
<li>jQuery:  almost feel like writing javascript short-hand notation.   Will take sometime to get used to the syntax.  Core library is very small (~30Kb)</li>
<li>YUI: there&#8217;s a lot being offered in this framework.  Get quite large (ZIP file: ~10MB!).  I just don&#8217;t like everything being stuffed inside the YUI namespace, even when I register my own namespace.   </li>
</ul>
<hr/>
<p><b>Tip 1:  Format your code well.</b><br />
Nothing is worse than writing a large ( or any) application with poor code readability.  As the application gets more complex, as it did in my case, having the ability to scan through the code and pin-point the hot-spot to fix is extremely helpful.  Simply by consistently indent the code with <strong>NO EXCEPTION</strong> and keep yourself to a high coding-standard, your code will look pretty, work well, and have less bugs.  The key is to do this as you code, not after everything has been done.  You think you won&#8217;t ever look at your code again once it&#8217;s done, well, <strong>YOU ARE WRONG</strong>!  </p>
<p>Once you are in the habit of formatting the code yourself, you become more aware of the &#8220;beauty&#8221;  of your code.  You&#8217;ll start seeing cool things, similar to the guys in Matrix see our world.  You&#8217;ll become Neil and fly through your code and feel its force-field.</p>
<p><a href='http://alexle.net/wp-content/uploads/2008/05/seethematrix.jpg'><img src="http://alexle.net/wp-content/uploads/2008/05/seethematrix-300x228.jpg" alt="" title="seethematrix" width="300" height="228" class="aligncenter size-medium wp-image-263" /></a></p>
<hr/>
<p><strong>Tip 2:  Having a high coding standard.</strong><br />
<a href='http://www.amazon.com/Code-Complete-Practical-Handbook-Construction/dp/0735619670/ref=pd_sim_b_njs_img_3'><img src="http://alexle.net/wp-content/uploads/2008/05/cc2e-cover-smallgif.jpg" alt="" title="Coding Standard" width="162" height="198" class="alignleft size-medium wp-image-264" align=left style="padding: 2px"/></a>The reason why you have to keep your code in order and of high standard with no exception is that I believe in the Broken-window theory (<a href="http://en.wikipedia.org/wiki/Fixing_Broken_Windows">wikipedia</a>).  Once there is a sub-standard spot in your code and you <strong>ACCEPT</strong> that it is there, you&#8217;ll more likely to repeat it and produce more sub-standard code.  Nobody vandalizes your code better than you are.  Soon, it will become an unmanageable, unreadable mess.  Imagine debug these kinds of code?  I&#8217;ll be cursing all day long.</p>
<p>I highly recommend the <strong><a href="http://www.amazon.com/Code-Complete-Practical-Handbook-Construction/dp/0735619670/ref=pd_sim_b_njs_img_3">Code Complete book</a></strong>.  It is thick enough to use as a pillow, but it is a mandatory read if you are serious about programming.</p>
<hr/>
<p><strong>Tip 3:  Explicitly write out your coding style and standard.</strong><br />
This is essential when you are working in a team with other people.  Also, once you have established a coding style guideline, you will spend less time on thinking about the formatting, how to name variables, how to organize your code.  I fondly remember DHH&#8217;s word:  constraint is liberation.  Yup, having a certain constraints will allow you to be more freely to do other productive programming.</p>
<hr/>
<p><strong>Tip 4. Namespacing your code</strong><br />
If you are develop something more complicated than an alert box, put your code inside namespaces to avoid cluttering up the global scope, reducing potential conflicts with accidental over-written from other scripts, and organizing your code much better.</p>
<p>Repeat after me:  <strong>Namespace your code, it&#8217;s easy.  Do it.</strong></p>
<p><strong>Example:</strong><br />
Our application is a JavaScript drawing program called JsPaint.  We can separate the code into different namespaces as follow:</p>
<pre name="code" class="javascript">
/* Include in your first included JS file */
var JsPaint = {
  Data: {}
  ,UI: {}
  ,Util: {}
};
</pre>
<p>To add more methods or classes to JsPaint.UI:</p>
<pre name="code" class="javascript">
JsPaint.UI = {
  Menu: {}
  ,MenuItem: {}
  ,Canvas: {}
  ,getCanvas:  function() { /* return reference to the canvas here */ }
};
</pre>
<p>To add a Renderer sub-namespace later on to the JsPaint.UI:</p>
<pre name="code" class="javascript">
JsPaint.UI.Renderer = {
  Simple: function() {} /* class */
  ,Fancy:  function() {} /* class */
};

/* define shortcut to Renderer */
var jsr = JsPaint.UI.Renderer;
var simpleRenderer = new jsr.Simple();
</pre>
<p>Namespace is awesome to organize your code.  However, if you have lots of level within your namespace, you can, and should, use <strong>aliases</strong> for the different namespaces.  By aliasing, you also reduce the amount of &#8220;dot&#8221; operations to query the object, thus helping the properties lookup faster.</p>
<hr/>
<p><b>Tip 5:  Putting comma-separator at the begining of the line.</b><br />
I ran into this post on Thomas Fuchs&#8217;s blog a couple days ago.  Thomas is the guy behind Scriptaculous.  I couldn&#8217;t help but smile.</p>
<p><a href='http://mir.aculo.us/2008/4/29/say-hello-to-twistori'><img src="http://alexle.net/wp-content/uploads/2008/05/js-trailing-comma1.png" alt="" title="js-trailing-comma1" width="444" height="447" class="aligncenter size-full wp-image-262" /></a></p>
<p>Internet Explorer is every picky about JSON format (I think this is good in a way, as it forces you to pay attention to the code).  If you leave an extra trailing comma, IE will silently crash, while good old FireFox still works just fine.</p>
<p>Example:</p>
<pre name="code" class="javascript">
var ieWontLikeThis = {
  isIEBadForYou:  true
  ,hoursWastedOnDebuggingIE:  function() { throw "Number Out Of Range";}
  ,noticeTheTrailingCommaBelow: true
  ,
}
</pre>
<p>The extra comma will cause IE to be so confused and throw up.</p>
<p>My solution is to always put comma right before your properties, so that you won&#8217;t end up forgetting about the extra comma.  The code may look ugly and weird a little bit at first, but you&#8217;ll save yourself lots of pain and aggravation down the road.  Moreover, you can comment out a properties without further re-formatting of the code.  If I don&#8217;t want the hoursWastedOnDebuggingIE() method, I only need to comment it out.  If you put the comma trailing the previous line, you will have to remember to remove it too.  Not fun.</p>
<p><strong>Bonus: </strong><br />
This coding style with the comma or the separator as the prefix is also useful for other languages as well, especially for SQL statements.  It helps with 1) List of Columns to be SELECT&#8217;ed, 2) WHERE conditions, 3) Different temp variables in Common Table Expression (SQL Server 2005).  (Besides that, I also force myself to indent the code in a consistent way, indentation matters!).</p>
<pre name="code" class="sql">
SELECT
  p.title
  ,p.description
  ,p.is_published
--  ,p.category_id   /* don't need this column*/
  ,a.user
  ,a.author_id
  ,p.created_at
FROM posts p
INNER JOIN author a
  ON p.author_id = a.author_id
WHERE a.user = 'alexle'
  AND p.type = 'post'
  AND p.is_published = true
--  AND p.category_id = 1   /* this line can be commented out without affecting the previous code */
ORDER BY p.created_at DESC
--   AND p.category_id  /* this line also can be commented out without affecting the code */
</pre>
<p>Another example with writing and debugging Common Table Expressions.  This comes directly from my experience with writing a humongous CTE in SQL Server 2005</p>
<pre name="code" class="sql">
WITH firstCTE AS (

)
-- SELECT * FROM firstCTE  /* uncomment this line to debug the first CTE */
, secondCTE AS (

)
-- SELECT * FROM firstCTE  /* uncomment this line to debug the second CTE */
, thirdCTE AS ( 

)
-- SELECT * FROM firstCTE  /* uncomment this line to debug the third CTE */

SELECT *
FROM firstCTE
INNER JOIN secondCTE
  ON ...
INNER JOIN thirdCTE
  ON ...
</pre>
<hr/>
<p><b>Tip: 6 Having fun with Function Arguments</b><br />
If you have to write functions with lots of arguments, well, you don&#8217;t have to.  Instead, pass an array (or hash to be exact) of parameters as the  argument and have your code handled it intelligently.  You have more flexibility as the parameters list can be changed anytime.  This technique is used extensively through out Prototype, Scriptaculous, and other frameworks such as jQuery, or ExtJs.</p>
<pre name="code" class="javascript">
JsPaint.UI.Canvas = function( options ) {
  var defaultOptions = {
    canvasId:     'canvas_container'
    ,width:       100
    ,height:      200
    ,menuItems:   [ "File", "Edit", "View", "Help" ]
  };  

  /* merging default options with the passed in options  */
  this.canvasId   = options ? ( options.canvasId || defaultOptions.canvasId ) : defaultOptions.canvasId;
  this.width      = options ? ( options.width || defaultOptions.width ): defaultOptions.width;
  this.height     = options ? ( options.height || defaultOptions.height ): defaultOptions.height;
  this.menuItems  = options ? ( options.menuItems || defaultOptions.menuItems ) : defaultOptions.menuItems;
};
</pre>
<p>I use a shortcut with the <a href="http://en.wikipedia.org/wiki/Ternary_logic">ternary operator</a> <strong>? :</strong> and the &#8220;or&#8221; operator || to quickly merge the options with the defaultOptions.</p>
<hr/>
<p><strong>Tip 7:  Using or operator || for Coalescing nullable values</strong><br />
If you need to choose the first not-null value from a list, you can use the || (&#8217;or&#8217;) operator.  Besides its usage as a logical boolean operator, || can be used as a fall-through-if-null operator, return the first non-null value.</p>
<pre name="code" class="javascript">
var width = options.width || defaultOptions.width || 100;
</pre>
<p>It will check for the options.width, if null, defaultOptions.width will be used, then finally 100 if both the previous variables are null.  </p>
<p>In SQL Server and MySQL, you can use the function COALESCE( csv_list_of_variables ) to do the same, e.g. getting the first non-null value;</p>
<hr/>
<p><strong>Tip 8:  Using ternary operator to reduce the amount of if-else in your code</strong><br />
I love the ternary operator.  It may look cryptic, but after a while, your code will be shortened quite a bit while still remains readable with proper formatting.  Nested ternary operations can be hard to read so it&#8217;s a matter of balancing between coding shorthand and code readability.</p>
<hr/>
<p><strong>Tip 9:  Function Arguments, enhanced with Prototype</strong><br />
Do you see how ugly our previous code to get the values from the arguments?  If you are using Prototype, you can shorten all the ugly manual merging with a one liner</p>
<pre name="code" class="javascript">
var JsPaint.UI.Canvas = function( options ) {
  var defaultOptions = {
    canvasId:     'canvas_container'
    ,width:       100
    ,height:      200
    ,menuItems:   [ "File", "Edit", "View", "Help" ]
  };  

  /* merge defaultOptions with options */
  options = Object.extend( defaultOptions, options );
  this.canvasId   = options.canvasId;
  this.width      = options.width;
  this.height     = options.height;
  this.menuItems  = options.menuItems;
};
</pre>
<p>Done!  <strong>Object.extend()</strong> merges all the options together so you can have fun writing other productive code.</p>
<hr/>
<p><strong>Tip 10: Optimize Loops</strong><br />
If you need to iterate through a large array, you should squeeze every bit of speed by caching the length.  There&#8217;s always a trade-off between speed and storage, and if you want speed, you must trade RAM for it.  The Prototype&#8217;s <a href="http://www.prototypejs.org/api/array">API page for Array</a> has an excellent example:</p>
<pre name="code" class="javascript">
// Custom loop with cached length property: maximum full-loop performance on very large arrays!
for (var index = 0, len = myArray.length; index < len; ++index) {
  var item = myArray[index];
  // Your code working on item here...
}
</pre>
<hr/>
<p><strong>Tip 11: Object Inheritance made easy with Prototype</strong><br />
Since Prototype version 1.6, you now have full support for inheritance for your Object-Oriented JavaScript application.  JavaScript has the support for inheritance, albeit not built-in, but it has never been easy to work with.  Before, I had to write hacks and came up with something monstrous, ugly, and kludgy in the end.  With Prototype, you get full support for inheritance for virtually free using <strong>Object.extend()</strong> and <strong>Class.create()</strong>.</p>
<p>To ready more about inheritance, consult the <a href="http://www.prototypejs.org/learn/class-inheritance">Prototype&#8217;s Tutorial page on Inheritance<br />
</a></p>
<hr/>
<p><strong>Tip 12:  Leveraging Prototype&#8217;s Internal Methods</strong><br />
I highly recommend you to read through Prototype&#8217;s source code.  The file contains more than 4000 lines of high-quality JavaScript code and you will learn a lot from doing so.  An example is <strong>Event.KEY_*</strong> attributes (~ line 3700), containing the numerical code for various keys so you don&#8217;t have to look them up or re-define them again.  Another example is the <strong>Prototype.emptyFunction</strong> attribute, which is an empty function.  I often use emptyFunction in my base classes to make it clear that these methods are <em>virtual methods</em>, to be overridden by the sub-classes.</p>
<p>Example:</p>
<pre name="code" class="javascript">
JsPaint.Shape.ShapeBase = Class.create( {
  initialize: function() {}

  /* only the object knows how to draw itself */
  ,draw: Prototype.emptyFunction

  /* only the object knows how to refresh the screen */
  ,refresh: Prototype.emptyFunction

} );

JsPaint.Shape.Rectangle = Class.create( JsPaint.Shape.ShapeBase, {
  initialize: function( $super, width, height, x, y ) {
    /* calling parent's constructor */
    $super();
  }

  ,draw: function( $super ) {
    /* drawing logic here */
  }

  ,refresh: function( $super ) {
    /* refresh logic here */
  }
} );

JsPaint.Shape.Square = Class.create( JsPaint.Shape.Rectangle, {
  initialize: function( $super, side, x, y ) {
    /* calling Rectangle's constructor */
    $super( side, side, x, y);
  }
  /* draw() and refresh() stay the same */
} );
</pre>
<hr/>
<p><strong>Tip 13:  Implementing Enumerable methods for your custom collections</strong><br />
For my application, I need to implement a generic sorted list that must behaves similar to a regular array while being optimized for speed.  I set out to write a hybrid data structure that uses binary sorting to keep the array always in-ordered.  I&#8217;ll publish the code in a separate post, but the interesting idea I want to share is the implementation of methods from the Enumerable interface, which helps working with the custom sorted list a lot more enjoyable.</p>
<p>From Prototype&#8217;s <a href="http://www.prototypejs.org/api/enumerable"><b>API page for Enumerable</b></a>, the methods are </p>
<ul>
<li>all</li>
<li>any</li>
<li>collect</li>
<li>detect</li>
<li>each</li>
<li>eachSlice</li>
<li>entries</li>
<li>find</li>
<li>findAll</li>
<li>grep</li>
<li>inGroupsOf</li>
<li>include</li>
<li>inject</li>
<li>invoke</li>
<li>map</li>
<li>max</li>
<li>member</li>
<li>min</li>
<li>partition</li>
<li>pluck</li>
<li>reject</li>
<li>select</li>
<li>size</li>
<li>sortBy</li>
<li>toArray</li>
<li>zip</li>
</ul>
<p>I did not implement many these methods for my collection (I didn&#8217;t need them all), but my favorite ones are each(), first(), last() (these 2 are not listed, but they are still my favorites).  Enumerable is a great time saver, implement it if you can.</p>
<hr/>
<p><strong>Tip 14:  A better Enumerable#each() implementation</strong><br />
The current implementation for Enumberable#each() in Prototype is not as nice and it&#8217;s cumbersome to break out from the loop.  I&#8217;m greedy and I want everything a native for-loop can offer:  item, its index, ability to break and continue, plus the piece of mind of not worrying about the index-out-of-range issue.  </p>
<p>Here is my so-called better each() implementation:</p>
<pre name="code" class="javascript">
  each: function( iterator ) {
		for( var i = 0, len = this.collection.length; i < len; ++i ) {
			if( typeof( temp = iterator( this.collection[i], i ) ) != 'undefined' &#038;&#038; !temp )
				break;
		}
	}
</pre>
<p>The trick is to only break when the iterator explicitly returns false.</p>
<p>Example Usage:</p>
<pre name="code" class="javascript">
var list = new SortedList ();
/* populate the list here */

/* iterating ... */
list.each( function( item, index ) {
  /* process here */
  item.process();

  /* skipping ...*/
  if( continueConditionIsTrue )
    return; /* this will returned 'undefined' back to the iterator */

  /* break out early */
  if( breakOutConditionIsTrue )
    return false;

} );
</pre>
<hr/>
<p><strong>Tip 15: Passing function reference:  The Strategy Pattern</strong><br />
Once you realize how flexible JavaScript is, you begin to have fun with it.  Passing function reference is a neat trick that can be very useful.  If you look at the each()&#8217;s implementation above, you see that the iterator function is being passed in as an argument variable.  The iterator is than invoked directly via that argument variable just as you would normally execute a function.  Neato!</p>
<p>I used this trick in my SortedList implementation and love it.  Since the items stored in the list are custom objects that do not implement IComparable interface (that you can&#8217;t do item.compareTo( otherItem) ), however, to sort them, I need to be able to compare 2 object together directly.  I implemented a <strong>comparator</strong> that contains (or encapsulate) the business logic for the object comparison.  Basically the SortedList doesn&#8217;t care on how the objects are constructed, as long as the comparator can give the correct comparison results, the list is guaranteed to work</p>
<p>Here is the constructor for my SortedList.  I used Prototype Class.create() to create a new class and the initialize() method is the constructor.</p>
<pre name="code" class="javascript">
/* I use Prototype */
var SortedList = Class.create( {
  initialize: function( options ) {
    this.collection = [];

    var defaultOptions = {
      comparator: function(a,b) { return ( a < b ) ? -1 : ( a == b ) ? 0 : 1; }
      ,jsonifier: function(a) { return a.toJSON() }
    };

    this.comparator = options ? options.comparator || defaultOptions.comparator : defaultOptions.comparator;
    this.jsonifier  = options ? options.jsonifier || defaultOptions.jsonifier : defaultOptions.jsonifier;
  }
} );
</pre>
<p>I have a default comparator which can be used for basic data types (int, float, double, etc.), or I can pass in a custom comparator in the options argument to override the default one.  The strategy for the comparison can be swapped out anytime and still the rest of the implementation remains unchanged.</p>
<p>The <strong>indexOf(item)</strong> function can be then implemented as follow:</p>
<pre name="code" class="javascript">
indexOf: function( item ) {
  if( this.comparator( this.collection[ 0 ], item ) == 0 )
    return 0;
  else if( this.comparator( this.collection[ this.collection.length - 1 ], item ) == 0 )
    return this.collection.length - 1;

  for( var i = 0, len = this.collection.length; i < len; ++i )
  {
    if( this.comparator( this.collection[ i ], item ) == 0 )
      return i;
  }

  return -1; // not found;
}
</pre>
<hr/>
<p><strong>Tip 16:  Closure</strong><br />
Closure is powerful.  Without this feature, JavaScript won&#8217;t be as flexible and robust as it is now.  There are lots of good tutorials on closure so I won&#8217;t be cover it again in depth.  I&#8217;ll provide a code sample instead.  Yup, show, don&#8217;t just tell.  The simplest example is to access the &#8220;this&#8221; keyword in a setTimeout or setInterval context.</p>
<p>Let&#8217;s have a StopWatch class that keeps track of its internal run time and update its display accordingly.  Here is a very simple implementation that I cooked up in 5 minutes</p>
<pre name="code" class="javascript">
var StopWatch = Class.create({
  initialize: function() {
    /* init these varialbe */
    this.runTime        = 0;
    this.tickDuration   = 100;  /* tick every 100 ms */
    this.timer          = null;
  }

  ,start: function() {
    /* exit if the stop watch already running */
    if( this.timer ) return; 

    var me = this;
    this.timer = setInterval( function() { me.tick() }, this.tickDuration );
  }

  ,tick: function() {
    this.runTime += this.tickDuration;
    this.updateDisplay();
  }

  ,stop: function() {
    clearInterval( this.timer );
  }

  ,updateDisplay: function() {
    /* update the time display here */;
  }

});

/* Now run the stop watches */
var exeriseStopWatch = new StopWatch();
exeriseStopWatch.start(); /* you'll see the time ticking here */

var cookingStopWatch = new StopWatch();
cookingStopWatch.start(); /* you'll see the time ticking here */

exeriseStopWatch.stop();
cookingStopWatch.stop();
</pre>
<p>In the <strong>start()</strong> method, we declare a &#8220;<em>me</em>&#8221; variable to hold the reference to the current object and if you remember, we can pass function references as variables within JavaScript.  Since the function defined within <strong>setInterval</strong> is still in the local scope of the start() method, we have access to the &#8220;me&#8221; variable &#8212; which again point back to &#8220;this&#8221; StopWatch.  </p>
<hr/>
<p><strong>Tip 17: Closure with Prototype Cool-aid</strong><br />
If you use Prototype, you can have a much nicer syntax for closure and accessing the &#8220;this&#8221; scope.  Let&#8217;s rewrite the start() function of our WtopWatch class.</p>
<pre name="code" class="javascript">
  ,start: function() {
    /* exit if the stop watch already running */
    if( this.timer ) return;
    this.timer = setInterval( this.tick.bind( this ), this.tickDuration );
  }
</pre>
<p>Prototype extends the native Function object within JavaScript with some neat wrappers, <strong>bind()</strong> is one of them.  The <a href="http://www.prototypejs.org/api/function/bind">explanation for function.bind()</a> :</p>
<blockquote><p>  Wraps the function in another, locking its execution scope to an object specified by thisObj.</p></blockquote>
<p>Your code suddenly becomes much clearer and it <strong>states the intention of what it does</strong>!  Prototype&#8217;s developers get the principle from the Ruby language:  optimizing the programmer&#8217;s fun and productivity.  These utility methods such as bind() and bindAsEventListener() just make writing JavaScript a lot more enjoyable and straightforward.</p>
<hr/>
<p><strong>Final Words</strong><br />
This is by far the longest post I have ever written in a single day.  I am excited to learn more about JavaScript, and I am more than glad to share my experience with everyone.  I hope you can get out a few good things from this post and apply in your everyday work.  </p>
<p>Let me know if you find any bugs and typo.  Disclaimer:  the code samples in this post have not been tested so point it out if you can.</p>
]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been working extensively with JavaScript for the past few weeks, developing an all-Javascript application (the code base is exceeding 2000 lines of JavaScript already).  Since the application needs to scale well with a large amount of dynamically generated elements, I have discovered, learend, and used quite a few shortcuts to boost the speed, minimize memory usage with mem-leak checks, and reduce file-size in general while still maintain the readability of the code.  </p>
<p>This article is mainly about the nuggets that I extract out from my experience.  I learned a few things from reading the source of <a href="http://www.prototypejs.org">PrototypeJS</a> and <a href="http://script.aculo.us/">Scriptaculous</a>, while I learned other things (ideas, concepts) from different languages such as Ruby (famous for one-liners).  I have to admit, nothing beats reading other people&#8217;s source code.  Prototype is extremely well-written and there are tons of programming gems that one can learn from.</p>
<p>A few tricks are possible only in JavaScript because it is NOT Java, or C#, or C, and it is extremely powerful and flexible.  With the Prototype cool-aid, Object-Oriented JavaScript is not only possible, but easy, standardized, and straight-forward to implement </p>
<p><b>Tip 0:  Use a JavaScript framework</b><br />
Pick a framework and use it.  Any framework is *much* better than no framework at all.  Different browser behaves differently and the framework will help smooth out those wrinkles.  You are simply insane if you are not using one.</p>
<p>Our menu comes with several choices:  so it&#8217;s a matter of personal preference.  The learning curve will a bit steep as you will have to Google alot for the API&#8217;s, but once you are familiar and comfortable, you will become a much better scripter.</p>
<ul>
<li>Prototype:  Easy to use.  One of the first that popularized the idea of frameworks.  Lowest learning curve with virtually NO dependencies (1 file, ~ 130Kb)</li>
<li>jQuery:  almost feel like writing javascript short-hand notation.   Will take sometime to get used to the syntax.  Core library is very small (~30Kb)</li>
<li>YUI: there&#8217;s a lot being offered in this framework.  Get quite large (ZIP file: ~10MB!).  I just don&#8217;t like everything being stuffed inside the YUI namespace, even when I register my own namespace.   </li>
</ul>
<hr/>
<p><b>Tip 1:  Format your code well.</b><br />
Nothing is worse than writing a large ( or any) application with poor code readability.  As the application gets more complex, as it did in my case, having the ability to scan through the code and pin-point the hot-spot to fix is extremely helpful.  Simply by consistently indent the code with <strong>NO EXCEPTION</strong> and keep yourself to a high coding-standard, your code will look pretty, work well, and have less bugs.  The key is to do this as you code, not after everything has been done.  You think you won&#8217;t ever look at your code again once it&#8217;s done, well, <strong>YOU ARE WRONG</strong>!  </p>
<p>Once you are in the habit of formatting the code yourself, you become more aware of the &#8220;beauty&#8221;  of your code.  You&#8217;ll start seeing cool things, similar to the guys in Matrix see our world.  You&#8217;ll become Neil and fly through your code and feel its force-field.</p>
<p><a href='http://alexle.net/wp-content/uploads/2008/05/seethematrix.jpg'><img src="http://alexle.net/wp-content/uploads/2008/05/seethematrix-300x228.jpg" alt="" title="seethematrix" width="300" height="228" class="aligncenter size-medium wp-image-263" /></a></p>
<hr/>
<p><strong>Tip 2:  Having a high coding standard.</strong><br />
<a href='http://www.amazon.com/Code-Complete-Practical-Handbook-Construction/dp/0735619670/ref=pd_sim_b_njs_img_3'><img src="http://alexle.net/wp-content/uploads/2008/05/cc2e-cover-smallgif.jpg" alt="" title="Coding Standard" width="162" height="198" class="alignleft size-medium wp-image-264" align=left style="padding: 2px"/></a>The reason why you have to keep your code in order and of high standard with no exception is that I believe in the Broken-window theory (<a href="http://en.wikipedia.org/wiki/Fixing_Broken_Windows">wikipedia</a>).  Once there is a sub-standard spot in your code and you <strong>ACCEPT</strong> that it is there, you&#8217;ll more likely to repeat it and produce more sub-standard code.  Nobody vandalizes your code better than you are.  Soon, it will become an unmanageable, unreadable mess.  Imagine debug these kinds of code?  I&#8217;ll be cursing all day long.</p>
<p>I highly recommend the <strong><a href="http://www.amazon.com/Code-Complete-Practical-Handbook-Construction/dp/0735619670/ref=pd_sim_b_njs_img_3">Code Complete book</a></strong>.  It is thick enough to use as a pillow, but it is a mandatory read if you are serious about programming.</p>
<hr/>
<p><strong>Tip 3:  Explicitly write out your coding style and standard.</strong><br />
This is essential when you are working in a team with other people.  Also, once you have established a coding style guideline, you will spend less time on thinking about the formatting, how to name variables, how to organize your code.  I fondly remember DHH&#8217;s word:  constraint is liberation.  Yup, having a certain constraints will allow you to be more freely to do other productive programming.</p>
<hr/>
<p><strong>Tip 4. Namespacing your code</strong><br />
If you are develop something more complicated than an alert box, put your code inside namespaces to avoid cluttering up the global scope, reducing potential conflicts with accidental over-written from other scripts, and organizing your code much better.</p>
<p>Repeat after me:  <strong>Namespace your code, it&#8217;s easy.  Do it.</strong></p>
<p><strong>Example:</strong><br />
Our application is a JavaScript drawing program called JsPaint.  We can separate the code into different namespaces as follow:</p>
<pre name="code" class="javascript">
/* Include in your first included JS file */
var JsPaint = {
  Data: {}
  ,UI: {}
  ,Util: {}
};
</pre>
<p>To add more methods or classes to JsPaint.UI:</p>
<pre name="code" class="javascript">
JsPaint.UI = {
  Menu: {}
  ,MenuItem: {}
  ,Canvas: {}
  ,getCanvas:  function() { /* return reference to the canvas here */ }
};
</pre>
<p>To add a Renderer sub-namespace later on to the JsPaint.UI:</p>
<pre name="code" class="javascript">
JsPaint.UI.Renderer = {
  Simple: function() {} /* class */
  ,Fancy:  function() {} /* class */
};

/* define shortcut to Renderer */
var jsr = JsPaint.UI.Renderer;
var simpleRenderer = new jsr.Simple();
</pre>
<p>Namespace is awesome to organize your code.  However, if you have lots of level within your namespace, you can, and should, use <strong>aliases</strong> for the different namespaces.  By aliasing, you also reduce the amount of &#8220;dot&#8221; operations to query the object, thus helping the properties lookup faster.</p>
<hr/>
<p><b>Tip 5:  Putting comma-separator at the begining of the line.</b><br />
I ran into this post on Thomas Fuchs&#8217;s blog a couple days ago.  Thomas is the guy behind Scriptaculous.  I couldn&#8217;t help but smile.</p>
<p><a href='http://mir.aculo.us/2008/4/29/say-hello-to-twistori'><img src="http://alexle.net/wp-content/uploads/2008/05/js-trailing-comma1.png" alt="" title="js-trailing-comma1" width="444" height="447" class="aligncenter size-full wp-image-262" /></a></p>
<p>Internet Explorer is every picky about JSON format (I think this is good in a way, as it forces you to pay attention to the code).  If you leave an extra trailing comma, IE will silently crash, while good old FireFox still works just fine.</p>
<p>Example:</p>
<pre name="code" class="javascript">
var ieWontLikeThis = {
  isIEBadForYou:  true
  ,hoursWastedOnDebuggingIE:  function() { throw "Number Out Of Range";}
  ,noticeTheTrailingCommaBelow: true
  ,
}
</pre>
<p>The extra comma will cause IE to be so confused and throw up.</p>
<p>My solution is to always put comma right before your properties, so that you won&#8217;t end up forgetting about the extra comma.  The code may look ugly and weird a little bit at first, but you&#8217;ll save yourself lots of pain and aggravation down the road.  Moreover, you can comment out a properties without further re-formatting of the code.  If I don&#8217;t want the hoursWastedOnDebuggingIE() method, I only need to comment it out.  If you put the comma trailing the previous line, you will have to remember to remove it too.  Not fun.</p>
<p><strong>Bonus: </strong><br />
This coding style with the comma or the separator as the prefix is also useful for other languages as well, especially for SQL statements.  It helps with 1) List of Columns to be SELECT&#8217;ed, 2) WHERE conditions, 3) Different temp variables in Common Table Expression (SQL Server 2005).  (Besides that, I also force myself to indent the code in a consistent way, indentation matters!).</p>
<pre name="code" class="sql">
SELECT
  p.title
  ,p.description
  ,p.is_published
--  ,p.category_id   /* don't need this column*/
  ,a.user
  ,a.author_id
  ,p.created_at
FROM posts p
INNER JOIN author a
  ON p.author_id = a.author_id
WHERE a.user = 'alexle'
  AND p.type = 'post'
  AND p.is_published = true
--  AND p.category_id = 1   /* this line can be commented out without affecting the previous code */
ORDER BY p.created_at DESC
--   AND p.category_id  /* this line also can be commented out without affecting the code */
</pre>
<p>Another example with writing and debugging Common Table Expressions.  This comes directly from my experience with writing a humongous CTE in SQL Server 2005</p>
<pre name="code" class="sql">
WITH firstCTE AS (

)
-- SELECT * FROM firstCTE  /* uncomment this line to debug the first CTE */
, secondCTE AS (

)
-- SELECT * FROM firstCTE  /* uncomment this line to debug the second CTE */
, thirdCTE AS ( 

)
-- SELECT * FROM firstCTE  /* uncomment this line to debug the third CTE */

SELECT *
FROM firstCTE
INNER JOIN secondCTE
  ON ...
INNER JOIN thirdCTE
  ON ...
</pre>
<hr/>
<p><b>Tip: 6 Having fun with Function Arguments</b><br />
If you have to write functions with lots of arguments, well, you don&#8217;t have to.  Instead, pass an array (or hash to be exact) of parameters as the  argument and have your code handled it intelligently.  You have more flexibility as the parameters list can be changed anytime.  This technique is used extensively through out Prototype, Scriptaculous, and other frameworks such as jQuery, or ExtJs.</p>
<pre name="code" class="javascript">
JsPaint.UI.Canvas = function( options ) {
  var defaultOptions = {
    canvasId:     'canvas_container'
    ,width:       100
    ,height:      200
    ,menuItems:   [ "File", "Edit", "View", "Help" ]
  };  

  /* merging default options with the passed in options  */
  this.canvasId   = options ? ( options.canvasId || defaultOptions.canvasId ) : defaultOptions.canvasId;
  this.width      = options ? ( options.width || defaultOptions.width ): defaultOptions.width;
  this.height     = options ? ( options.height || defaultOptions.height ): defaultOptions.height;
  this.menuItems  = options ? ( options.menuItems || defaultOptions.menuItems ) : defaultOptions.menuItems;
};
</pre>
<p>I use a shortcut with the <a href="http://en.wikipedia.org/wiki/Ternary_logic">ternary operator</a> <strong>? :</strong> and the &#8220;or&#8221; operator || to quickly merge the options with the defaultOptions.</p>
<hr/>
<p><strong>Tip 7:  Using or operator || for Coalescing nullable values</strong><br />
If you need to choose the first not-null value from a list, you can use the || (&#8217;or&#8217;) operator.  Besides its usage as a logical boolean operator, || can be used as a fall-through-if-null operator, return the first non-null value.</p>
<pre name="code" class="javascript">
var width = options.width || defaultOptions.width || 100;
</pre>
<p>It will check for the options.width, if null, defaultOptions.width will be used, then finally 100 if both the previous variables are null.  </p>
<p>In SQL Server and MySQL, you can use the function COALESCE( csv_list_of_variables ) to do the same, e.g. getting the first non-null value;</p>
<hr/>
<p><strong>Tip 8:  Using ternary operator to reduce the amount of if-else in your code</strong><br />
I love the ternary operator.  It may look cryptic, but after a while, your code will be shortened quite a bit while still remains readable with proper formatting.  Nested ternary operations can be hard to read so it&#8217;s a matter of balancing between coding shorthand and code readability.</p>
<hr/>
<p><strong>Tip 9:  Function Arguments, enhanced with Prototype</strong><br />
Do you see how ugly our previous code to get the values from the arguments?  If you are using Prototype, you can shorten all the ugly manual merging with a one liner</p>
<pre name="code" class="javascript">
var JsPaint.UI.Canvas = function( options ) {
  var defaultOptions = {
    canvasId:     'canvas_container'
    ,width:       100
    ,height:      200
    ,menuItems:   [ "File", "Edit", "View", "Help" ]
  };  

  /* merge defaultOptions with options */
  options = Object.extend( defaultOptions, options );
  this.canvasId   = options.canvasId;
  this.width      = options.width;
  this.height     = options.height;
  this.menuItems  = options.menuItems;
};
</pre>
<p>Done!  <strong>Object.extend()</strong> merges all the options together so you can have fun writing other productive code.</p>
<hr/>
<p><strong>Tip 10: Optimize Loops</strong><br />
If you need to iterate through a large array, you should squeeze every bit of speed by caching the length.  There&#8217;s always a trade-off between speed and storage, and if you want speed, you must trade RAM for it.  The Prototype&#8217;s <a href="http://www.prototypejs.org/api/array">API page for Array</a> has an excellent example:</p>
<pre name="code" class="javascript">
// Custom loop with cached length property: maximum full-loop performance on very large arrays!
for (var index = 0, len = myArray.length; index < len; ++index) {
  var item = myArray[index];
  // Your code working on item here...
}
</pre>
<hr/>
<p><strong>Tip 11: Object Inheritance made easy with Prototype</strong><br />
Since Prototype version 1.6, you now have full support for inheritance for your Object-Oriented JavaScript application.  JavaScript has the support for inheritance, albeit not built-in, but it has never been easy to work with.  Before, I had to write hacks and came up with something monstrous, ugly, and kludgy in the end.  With Prototype, you get full support for inheritance for virtually free using <strong>Object.extend()</strong> and <strong>Class.create()</strong>.</p>
<p>To ready more about inheritance, consult the <a href="http://www.prototypejs.org/learn/class-inheritance">Prototype&#8217;s Tutorial page on Inheritance<br />
</a></p>
<hr/>
<p><strong>Tip 12:  Leveraging Prototype&#8217;s Internal Methods</strong><br />
I highly recommend you to read through Prototype&#8217;s source code.  The file contains more than 4000 lines of high-quality JavaScript code and you will learn a lot from doing so.  An example is <strong>Event.KEY_*</strong> attributes (~ line 3700), containing the numerical code for various keys so you don&#8217;t have to look them up or re-define them again.  Another example is the <strong>Prototype.emptyFunction</strong> attribute, which is an empty function.  I often use emptyFunction in my base classes to make it clear that these methods are <em>virtual methods</em>, to be overridden by the sub-classes.</p>
<p>Example:</p>
<pre name="code" class="javascript">
JsPaint.Shape.ShapeBase = Class.create( {
  initialize: function() {}

  /* only the object knows how to draw itself */
  ,draw: Prototype.emptyFunction

  /* only the object knows how to refresh the screen */
  ,refresh: Prototype.emptyFunction

} );

JsPaint.Shape.Rectangle = Class.create( JsPaint.Shape.ShapeBase, {
  initialize: function( $super, width, height, x, y ) {
    /* calling parent's constructor */
    $super();
  }

  ,draw: function( $super ) {
    /* drawing logic here */
  }

  ,refresh: function( $super ) {
    /* refresh logic here */
  }
} );

JsPaint.Shape.Square = Class.create( JsPaint.Shape.Rectangle, {
  initialize: function( $super, side, x, y ) {
    /* calling Rectangle's constructor */
    $super( side, side, x, y);
  }
  /* draw() and refresh() stay the same */
} );
</pre>
<hr/>
<p><strong>Tip 13:  Implementing Enumerable methods for your custom collections</strong><br />
For my application, I need to implement a generic sorted list that must behaves similar to a regular array while being optimized for speed.  I set out to write a hybrid data structure that uses binary sorting to keep the array always in-ordered.  I&#8217;ll publish the code in a separate post, but the interesting idea I want to share is the implementation of methods from the Enumerable interface, which helps working with the custom sorted list a lot more enjoyable.</p>
<p>From Prototype&#8217;s <a href="http://www.prototypejs.org/api/enumerable"><b>API page for Enumerable</b></a>, the methods are </p>
<ul>
<li>all</li>
<li>any</li>
<li>collect</li>
<li>detect</li>
<li>each</li>
<li>eachSlice</li>
<li>entries</li>
<li>find</li>
<li>findAll</li>
<li>grep</li>
<li>inGroupsOf</li>
<li>include</li>
<li>inject</li>
<li>invoke</li>
<li>map</li>
<li>max</li>
<li>member</li>
<li>min</li>
<li>partition</li>
<li>pluck</li>
<li>reject</li>
<li>select</li>
<li>size</li>
<li>sortBy</li>
<li>toArray</li>
<li>zip</li>
</ul>
<p>I did not implement many these methods for my collection (I didn&#8217;t need them all), but my favorite ones are each(), first(), last() (these 2 are not listed, but they are still my favorites).  Enumerable is a great time saver, implement it if you can.</p>
<hr/>
<p><strong>Tip 14:  A better Enumerable#each() implementation</strong><br />
The current implementation for Enumberable#each() in Prototype is not as nice and it&#8217;s cumbersome to break out from the loop.  I&#8217;m greedy and I want everything a native for-loop can offer:  item, its index, ability to break and continue, plus the piece of mind of not worrying about the index-out-of-range issue.  </p>
<p>Here is my so-called better each() implementation:</p>
<pre name="code" class="javascript">
  each: function( iterator ) {
		for( var i = 0, len = this.collection.length; i < len; ++i ) {
			if( typeof( temp = iterator( this.collection[i], i ) ) != 'undefined' &#038;&#038; !temp )
				break;
		}
	}
</pre>
<p>The trick is to only break when the iterator explicitly returns false.</p>
<p>Example Usage:</p>
<pre name="code" class="javascript">
var list = new SortedList ();
/* populate the list here */

/* iterating ... */
list.each( function( item, index ) {
  /* process here */
  item.process();

  /* skipping ...*/
  if( continueConditionIsTrue )
    return; /* this will returned 'undefined' back to the iterator */

  /* break out early */
  if( breakOutConditionIsTrue )
    return false;

} );
</pre>
<hr/>
<p><strong>Tip 15: Passing function reference:  The Strategy Pattern</strong><br />
Once you realize how flexible JavaScript is, you begin to have fun with it.  Passing function reference is a neat trick that can be very useful.  If you look at the each()&#8217;s implementation above, you see that the iterator function is being passed in as an argument variable.  The iterator is than invoked directly via that argument variable just as you would normally execute a function.  Neato!</p>
<p>I used this trick in my SortedList implementation and love it.  Since the items stored in the list are custom objects that do not implement IComparable interface (that you can&#8217;t do item.compareTo( otherItem) ), however, to sort them, I need to be able to compare 2 object together directly.  I implemented a <strong>comparator</strong> that contains (or encapsulate) the business logic for the object comparison.  Basically the SortedList doesn&#8217;t care on how the objects are constructed, as long as the comparator can give the correct comparison results, the list is guaranteed to work</p>
<p>Here is the constructor for my SortedList.  I used Prototype Class.create() to create a new class and the initialize() method is the constructor.</p>
<pre name="code" class="javascript">
/* I use Prototype */
var SortedList = Class.create( {
  initialize: function( options ) {
    this.collection = [];

    var defaultOptions = {
      comparator: function(a,b) { return ( a < b ) ? -1 : ( a == b ) ? 0 : 1; }
      ,jsonifier: function(a) { return a.toJSON() }
    };

    this.comparator = options ? options.comparator || defaultOptions.comparator : defaultOptions.comparator;
    this.jsonifier  = options ? options.jsonifier || defaultOptions.jsonifier : defaultOptions.jsonifier;
  }
} );
</pre>
<p>I have a default comparator which can be used for basic data types (int, float, double, etc.), or I can pass in a custom comparator in the options argument to override the default one.  The strategy for the comparison can be swapped out anytime and still the rest of the implementation remains unchanged.</p>
<p>The <strong>indexOf(item)</strong> function can be then implemented as follow:</p>
<pre name="code" class="javascript">
indexOf: function( item ) {
  if( this.comparator( this.collection[ 0 ], item ) == 0 )
    return 0;
  else if( this.comparator( this.collection[ this.collection.length - 1 ], item ) == 0 )
    return this.collection.length - 1;

  for( var i = 0, len = this.collection.length; i < len; ++i )
  {
    if( this.comparator( this.collection[ i ], item ) == 0 )
      return i;
  }

  return -1; // not found;
}
</pre>
<hr/>
<p><strong>Tip 16:  Closure</strong><br />
Closure is powerful.  Without this feature, JavaScript won&#8217;t be as flexible and robust as it is now.  There are lots of good tutorials on closure so I won&#8217;t be cover it again in depth.  I&#8217;ll provide a code sample instead.  Yup, show, don&#8217;t just tell.  The simplest example is to access the &#8220;this&#8221; keyword in a setTimeout or setInterval context.</p>
<p>Let&#8217;s have a StopWatch class that keeps track of its internal run time and update its display accordingly.  Here is a very simple implementation that I cooked up in 5 minutes</p>
<pre name="code" class="javascript">
var StopWatch = Class.create({
  initialize: function() {
    /* init these varialbe */
    this.runTime        = 0;
    this.tickDuration   = 100;  /* tick every 100 ms */
    this.timer          = null;
  }

  ,start: function() {
    /* exit if the stop watch already running */
    if( this.timer ) return; 

    var me = this;
    this.timer = setInterval( function() { me.tick() }, this.tickDuration );
  }

  ,tick: function() {
    this.runTime += this.tickDuration;
    this.updateDisplay();
  }

  ,stop: function() {
    clearInterval( this.timer );
  }

  ,updateDisplay: function() {
    /* update the time display here */;
  }

});

/* Now run the stop watches */
var exeriseStopWatch = new StopWatch();
exeriseStopWatch.start(); /* you'll see the time ticking here */

var cookingStopWatch = new StopWatch();
cookingStopWatch.start(); /* you'll see the time ticking here */

exeriseStopWatch.stop();
cookingStopWatch.stop();
</pre>
<p>In the <strong>start()</strong> method, we declare a &#8220;<em>me</em>&#8221; variable to hold the reference to the current object and if you remember, we can pass function references as variables within JavaScript.  Since the function defined within <strong>setInterval</strong> is still in the local scope of the start() method, we have access to the &#8220;me&#8221; variable &#8212; which again point back to &#8220;this&#8221; StopWatch.  </p>
<hr/>
<p><strong>Tip 17: Closure with Prototype Cool-aid</strong><br />
If you use Prototype, you can have a much nicer syntax for closure and accessing the &#8220;this&#8221; scope.  Let&#8217;s rewrite the start() function of our WtopWatch class.</p>
<pre name="code" class="javascript">
  ,start: function() {
    /* exit if the stop watch already running */
    if( this.timer ) return;
    this.timer = setInterval( this.tick.bind( this ), this.tickDuration );
  }
</pre>
<p>Prototype extends the native Function object within JavaScript with some neat wrappers, <strong>bind()</strong> is one of them.  The <a href="http://www.prototypejs.org/api/function/bind">explanation for function.bind()</a> :</p>
<blockquote><p>  Wraps the function in another, locking its execution scope to an object specified by thisObj.</p></blockquote>
<p>Your code suddenly becomes much clearer and it <strong>states the intention of what it does</strong>!  Prototype&#8217;s developers get the principle from the Ruby language:  optimizing the programmer&#8217;s fun and productivity.  These utility methods such as bind() and bindAsEventListener() just make writing JavaScript a lot more enjoyable and straightforward.</p>
<hr/>
<p><strong>Final Words</strong><br />
This is by far the longest post I have ever written in a single day.  I am excited to learn more about JavaScript, and I am more than glad to share my experience with everyone.  I hope you can get out a few good things from this post and apply in your everyday work.  </p>
<p>Let me know if you find any bugs and typo.  Disclaimer:  the code samples in this post have not been tested so point it out if you can.</p>
]]></content:encoded>
			<wfw:commentRss>http://alexle.net/archives/260/feed</wfw:commentRss>
		</item>
	</channel>
</rss>

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