<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-1078898499337496912</id><updated>2012-01-27T00:56:07.994-08:00</updated><category term='PHP'/><category term='Guest Author'/><category term='jQuery'/><category term='jTruncate'/><category term='Hibernate'/><category term='Kwicks'/><category term='Misc'/><category term='Asciible'/><category term='JavaScript'/><category term='Blogger'/><category term='Java'/><category term='Algorithms'/><category term='Politics'/><category term='Photoshop'/><title type='text'>jMar's Blog</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://blog.jeremymartin.name/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://blog.jeremymartin.name/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Jeremy Martin</name><uri>http://www.blogger.com/profile/03514319709844297772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>28</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1078898499337496912.post-4889894249935806989</id><published>2008-06-26T13:40:00.001-07:00</published><updated>2008-06-26T13:53:39.976-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Kwicks'/><category scheme='http://www.blogger.com/atom/ns#' term='jQuery'/><title type='text'>Kwicks 1.5.1 Released!!!111!!</title><content type='html'>&lt;img src="http://jmar777.googlecode.com/svn/trunk/images/fail_dog.jpg" class="no-border" /&gt;&lt;br /&gt;
&lt;p&gt;So it turns out that people didn't really like the "&lt;a href="http://media.ebaumsworld.com/picture/e5hansej/1208060712814.jpg" target="new"&gt;Invalid Argument&lt;/a&gt;" error that Kwicks 1.5 was throwing in IE7+.&lt;/p&gt;

&lt;p&gt;Kwicks 1.5.1 fixes the bug and is &lt;a href="http://www.jeremymartin.name/projects.php?project=kwicks"&gt;ready for download&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once again, I would like to thank R&amp;#250;bel Mujica for his role in identifying and fixing the bug.  I would also like to thank everyone else who has shown an interest in the Kwicks plugin and for all of your invaluable input!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1078898499337496912-4889894249935806989?l=blog.jeremymartin.name' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jeremymartin.name/feeds/4889894249935806989/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1078898499337496912&amp;postID=4889894249935806989' title='81 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/4889894249935806989'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/4889894249935806989'/><link rel='alternate' type='text/html' href='http://blog.jeremymartin.name/2008/06/kwicks-151-released111.html' title='Kwicks 1.5.1 Released!!!111!!'/><author><name>Jeremy Martin</name><uri>http://www.blogger.com/profile/03514319709844297772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>81</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1078898499337496912.post-838382711513229574</id><published>2008-06-17T07:03:00.000-07:00</published><updated>2008-06-17T07:59:02.764-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Kwicks'/><category scheme='http://www.blogger.com/atom/ns#' term='jQuery'/><title type='text'>Kwicks 1.5 Released!</title><content type='html'>&lt;a href="http://www.jeremymartin.name/projects.php?project=kwicks" title="Kwicks for jQuery"&gt;&lt;img style="float: left; margin:0 15px 0 0;" class="no-border" src="http://jmar777.googlecode.com/svn/trunk/images/kwicks/kwicks1_5.png" alt="Kwicks 1.5" /&gt;&lt;/a&gt;
&lt;p&gt;Well I'm happy to announce that I have finally wrapped up the v1.5 update to the Kwicks plugin.  Kwicks 1.5 builds upon the original release in several big ways - here is a summary of what's different:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;
    &lt;strong&gt;Vertical Mode!&lt;/strong&gt;
    &lt;p&gt;This was a common request, so there was no way I could leave it out of this release.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;strong&gt;Min vs. Max&lt;/strong&gt;
    &lt;p&gt;The previous release required developers to specify the "max" width of the active kwick.  As of v1.5, developers may now opt to specify the width/height of all of all of the non-active kwicks instead.  This feature doesn't really add new functionality, but is merely offered as a convenience.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;strong&gt;Sticky Mode&lt;/strong&gt;
    &lt;p&gt;When sticky mode is enabled, one kwick will always be open.  This allows for more of an "accordion" type experience.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;strong&gt;Custom Trigger Event&lt;/strong&gt;
    &lt;p&gt;Kwicks 1.5 lets you specify the trigger event for the animation.  The default is still 'mouseover', but many users had wanted to use 'click' in instead.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;strong&gt;Smoother Animations&lt;/strong&gt;
    &lt;p&gt;This release I did some refactoring of the code behind the animations.  Several calculations were moved outside of the inner loops allowing for a less tasking, and consequently smoother, animation.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;strong&gt;Packed Script&lt;/strong&gt;
    &lt;p&gt;While this release still comes with fully commented and readable code, it also comes with a packed version which is far better for production use.  The new packed version is only 2.4 KB, which is actually smaller than the original release.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All in all this is a huge addition to the original version - many of the excellent suggestions I have received were addressed, and I hope that you will find the added flexibility more helpful than confusing.  I always believe simplicity is key, so I have tried to keep that in mind as the new features were added.  So what are you waiting for?  Go &lt;a href="http://www.jeremymartin.name/projects.php?project=kwicks" title="Kwicks for jQuery"&gt;check it out&lt;/a&gt;!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1078898499337496912-838382711513229574?l=blog.jeremymartin.name' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jeremymartin.name/feeds/838382711513229574/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1078898499337496912&amp;postID=838382711513229574' title='122 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/838382711513229574'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/838382711513229574'/><link rel='alternate' type='text/html' href='http://blog.jeremymartin.name/2008/06/kwicks-15-released.html' title='Kwicks 1.5 Released!'/><author><name>Jeremy Martin</name><uri>http://www.blogger.com/profile/03514319709844297772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>122</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1078898499337496912.post-503588662727098910</id><published>2008-05-28T07:51:00.000-07:00</published><updated>2008-05-28T07:56:51.247-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Photoshop'/><title type='text'>A "Dirty" Photoshop Tutorial</title><content type='html'>&lt;p&gt;Well, despite being a long time user of Photoshop, I've never sat down and attempted to make a tutorial.  I realize that the web is chock full of text effects for Photoshop, but this is a particular look that I haven't seen described before.  During the tutorial I share a couple of the hot-keys that I employ most often, so I'll apologize to the Mac users for only providing the Windows version (where they differ).  From what I understand, they're all pretty close... so that's that.  Let's dig in...&lt;/p&gt;

&lt;h3&gt;Create a New Project&lt;/h3&gt;
&lt;p&gt;Press Ctrl + 'N' to open a dialog for creating a new project.  Normally I work at higher resolutions, but for the sake of this tutorial I chose 640px by 480px.&lt;/p&gt;
&lt;p&gt;
 &lt;a href="http://jmar777.googlecode.com/svn/trunk/images/photoshop/dirty/new.png" target="new"&gt;
  &lt;img src="http://jmar777.googlecode.com/svn/trunk/images/photoshop/dirty/new_thumb.png" class="no-border" /&gt;
 &lt;/a&gt;
&lt;/p&gt;
 
&lt;h3&gt;Create a Background&lt;/h3&gt;
&lt;p&gt;Something simple here will do.  I set my foreground and background colors to darker shades of blue (#2C326E and #2D304A respectively).  Pressing Shift + 'G' will let you toggle between your gradient and bucket tools.  Using the gradient tool, click and drag your mouse from the upper left to the bottom right corners of the canvas.  Your canvas should now look like this:&lt;/p&gt;
&lt;p&gt;
 &lt;a href="http://jmar777.googlecode.com/svn/trunk/images/photoshop/dirty/blue_gradient.jpg" target="new"&gt;
  &lt;img src="http://jmar777.googlecode.com/svn/trunk/images/photoshop/dirty/blue_gradient_thumb.jpg" class="no-border" /&gt;
 &lt;/a&gt;
&lt;/p&gt;
 
&lt;h3&gt;Create Dirt Layer&lt;/h3&gt;
&lt;p&gt;Press Ctrl + Alt + Shift + 'N' to create a new layer.  We're going to create a new gradient just like we did in the step above, but this time, select two different shades of brown.  I chose #A2702F and #7F561E for the foreground and background respectively.  Your canvas should now look like this:&lt;/p&gt;
&lt;p&gt;
 &lt;a href="http://jmar777.googlecode.com/svn/trunk/images/photoshop/dirty/brown_gradient.jpg" target="new"&gt;
  &lt;img src="http://jmar777.googlecode.com/svn/trunk/images/photoshop/dirty/brown_gradient_thumb.jpg" class="no-border" /&gt;
 &lt;/a&gt;
&lt;/p&gt;
 
&lt;h3&gt;Add Noise to Dirt Layer&lt;/h3&gt;
&lt;p&gt;Next, in order to simulate the gritty nature of dirt, we're going to add a Noise filter to our dirt layer.  Click Filter &amp;gt; Noise &amp;gt; Add Noise...&lt;/p&gt;
&lt;p&gt;I used the options shown in the following image:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://jmar777.googlecode.com/svn/trunk/images/photoshop/dirty/add_noise.png" class="no-border" /&gt;&lt;/p&gt;
 
&lt;h3&gt;Add Text&lt;/h3&gt;
&lt;p&gt;Next we want to add some text.  The exact font you use isn't important, although I have found that "round" works better than "sharp" for this effect.  Also, you will want the font to be sufficiently thick (i.e., don't use Arial Narrow).  I chose a font called "Elephant" and used 170pt for the size.  The color is of no consequence here.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://jmar777.googlecode.com/svn/trunk/images/photoshop/dirty/add_text.jpg" class="no-border" /&gt;&lt;/p&gt;
 
&lt;h3&gt;Create Mask from Text&lt;/h3&gt;
&lt;p&gt;This step requires performing the following actions:&lt;/p&gt;
&lt;ul&gt;
 &lt;li&gt;Hide the text layer by clicking on the corresponding "eye" symbol.&lt;/li&gt;
 &lt;li&gt;Select the dirt layer.&lt;/li&gt;
 &lt;li&gt;Click the 'T' on the text layer while holding the Ctrl key.&lt;/li&gt;
 &lt;li&gt;You should now see that the outline of the text is selected.&lt;/li&gt;
 &lt;li&gt;Click the "Add Layer Mask" button shown below:&lt;br /&gt;
  &lt;img src="http://jmar777.googlecode.com/svn/trunk/images/photoshop/dirty/add_mask.png" class="no-border" /&gt;
 &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Your canvas should now look like this:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://jmar777.googlecode.com/svn/trunk/images/photoshop/dirty/masked_text.jpg" class="no-border" /&gt;&lt;/p&gt;
 
&lt;h3&gt;Add Loose Grains of Dirt&lt;/h3&gt;
&lt;p&gt;This is where we want to start adding in the random grains of dirt to make this look more natural.  This step requires performing the following actions:&lt;/p&gt;
&lt;ul&gt;
 &lt;li&gt;Select the brush tool (press 'B').&lt;/li&gt;
 &lt;li&gt;Choose a grainy looking brush.  I chose one of the default brushes as shown below:&lt;br /&gt;
  &lt;img src="http://jmar777.googlecode.com/svn/trunk/images/photoshop/dirty/select_brush.png" class="no-border" /&gt;
 &lt;/li&gt;
 &lt;li&gt;Now select the dirt layer's mask by clicking on the layer mask thumbnail, as shown below:&lt;br /&gt;
  &lt;img src="http://jmar777.googlecode.com/svn/trunk/images/photoshop/dirty/select_mask.png" class="no-border" /&gt;
 &lt;/li&gt;
 &lt;li&gt;Ensure that your foreground color is white.&lt;/li&gt;
 &lt;li&gt;Now you need to rely on your artistic eye a bit and click around in various places to reveal the dirt texture behind the mask.  Note that you don't want to drag the brush while clicking, since streaks will not look natural.  Mine ended up looking like this:&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="http://jmar777.googlecode.com/svn/trunk/images/photoshop/dirty/add_dirt.jpg" class="no-border" /&gt;&lt;/p&gt;
&lt;ul&gt;
 &lt;li&gt;The scattered dirt effect doesn't look quite right, so now we're going to switch the foreground color to black and selectively remove some of the dirt.  Mine ended up looking like this:&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="http://jmar777.googlecode.com/svn/trunk/images/photoshop/dirty/remove_dirt.jpg" class="no-border" /&gt;&lt;/p&gt;
 
&lt;h3&gt;Add Depth to the Dirt&lt;/h3&gt;
&lt;p&gt;The layer mask is finished now, but the dirt looks too flat.  Double click on the dirt layer to bring up the Layer Style dialog.  Make sure that "Layer Mask Hides Effects" is &lt;strong&gt;not&lt;/strong&gt; checked.  Now add a drop shadow with the following properties:&lt;/p&gt;
&lt;p&gt;
 &lt;a href="http://jmar777.googlecode.com/svn/trunk/images/photoshop/dirty/add_drop_shadow.png" target="new"&gt;
  &lt;img src="http://jmar777.googlecode.com/svn/trunk/images/photoshop/dirty/add_drop_shadow_thumb.png" class="no-border" /&gt;
 &lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;For the color, I used #3A2900.&lt;/p&gt;
&lt;p&gt;It's getting closer, but let's add a gradient overlay to give the light a little more "play" on the dirt.  I used the following properties:&lt;/p&gt;
&lt;p&gt;
 &lt;a href="http://jmar777.googlecode.com/svn/trunk/images/photoshop/dirty/add_gradient_overlay.png" target="new"&gt;
  &lt;img src="http://jmar777.googlecode.com/svn/trunk/images/photoshop/dirty/add_gradient_overlay_thumb.png" class="no-border" /&gt;
 &lt;/a&gt;
&lt;/p&gt;
 
&lt;h3&gt;Smooth Dirt&lt;/h3&gt;
&lt;p&gt;Some of you may wish to stop here, but I found that the Noise filter had left the dirt looking a little too grainy for the look I was after.  To smooth it out a bit, I unlinked the layer mask from the dirt layer by clicking the unlink mask button...&lt;/p&gt;
&lt;p&gt;&lt;img src="http://jmar777.googlecode.com/svn/trunk/images/photoshop/dirty/unlink_mask.png" class="no-border" /&gt;&lt;/p&gt;
&lt;p&gt;...and then I applied a very light Gaussian Blur (Filter &amp;gt; Blur &amp;gt; Gaussian Blur...) to the dirt layer:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://jmar777.googlecode.com/svn/trunk/images/photoshop/dirty/add_blur.jpg" class="no-border" /&gt;&lt;/p&gt;
 
&lt;p&gt;That's it!  Here's the finished effect:&lt;/p&gt;
&lt;p&gt;
 &lt;a href="http://jmar777.googlecode.com/svn/trunk/images/photoshop/dirty/finished.jpg" target="new"&gt;
  &lt;img src="http://jmar777.googlecode.com/svn/trunk/images/photoshop/dirty/finished_thumb.jpg" class="no-border" /&gt;
 &lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Mixing the random characteristics of scattered dirt with purposeful lettering can be tricky, but I feel this effect does a decent job of providing just that.  If you have any suggestions on how to improve the realism, please comment!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1078898499337496912-503588662727098910?l=blog.jeremymartin.name' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jeremymartin.name/feeds/503588662727098910/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1078898499337496912&amp;postID=503588662727098910' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/503588662727098910'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/503588662727098910'/><link rel='alternate' type='text/html' href='http://blog.jeremymartin.name/2008/05/dirty-photoshop-tutorial.html' title='A &quot;Dirty&quot; Photoshop Tutorial'/><author><name>Jeremy Martin</name><uri>http://www.blogger.com/profile/03514319709844297772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1078898499337496912.post-3309892403124930267</id><published>2008-05-23T10:13:00.000-07:00</published><updated>2008-05-28T07:51:26.239-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Blogger'/><title type='text'>How to Fix the Blogger Comment System</title><content type='html'>&lt;p&gt;
I'll be honest - I really like Blogger.  Despite the fact that nearly every co-blogger I know has urged me to give Wordpress a try, I'm still (mostly) satisfied with what I've got.  I serve static pages and other content myself, and let Google worry about hosting the blogs that account for over 90% of my total traffic.  However, there is one thing, in my opinion, that is unforgivably lacking in Blogger: the comment system.&lt;/p&gt;

&lt;p&gt;The comment system is so abysmal that I'm literally on the verge of creating my own message board that I can simply embed in an iframe.  If I weren't so packed for time lately, you could consider it done.  However, before I launch another harder-than-I-thought-at-first project, let me share with you the features that I believe, for the most part, any blogging platform should afford.&lt;/p&gt;

&lt;p&gt;So here they are, in no particular order:&lt;/p&gt;

&lt;ol&gt;
 &lt;li&gt;
  &lt;h3&gt;Unique Styling for Author Comments&lt;/h3&gt;
  &lt;p&gt;This one seems obvious to me.  Every other message board on the planet does this, yet Blogger currently offers no CSS accessible way to distinguish an author comment from a user comment.  I've previously discussed a &lt;strike&gt;hack&lt;/strike&gt; method using JavaScript to accomplish &lt;a href="http://blog.jeremymartin.name/2008/02/blogger-trick-style-author-comments.html"&gt;author comment styling&lt;/a&gt;, but it's ridiculously more painful than it should be.&lt;/p&gt;
 &lt;/li&gt;
 &lt;li&gt;
  &lt;h3&gt;Threaded Comments&lt;/h3&gt;
  &lt;p&gt;This one's pretty straight forward - users should have the option of replying to a particular comment, rather than being forced into a flat discussion.  Tree style comment threads allow for individual conversations to be self contained.&lt;/p&gt;
 &lt;/li&gt;
 &lt;li&gt;
  &lt;h3&gt;Collapsible Threads&lt;/h3&gt;
  &lt;p&gt;This feature is obviously dependent on the previous one.  But assuming threaded comments were implemented, I would expect the ability to collapse a thread that I was not interested in.  Think Digg...&lt;/p&gt;
 &lt;/li&gt;
 &lt;li&gt;
  &lt;h3&gt;Get Rid of that Separate Comment Page!&lt;/h3&gt;
  &lt;p&gt;Why oh why am I taken to another page just to leave a comment?  Can there possibly be a good explanation for this?&lt;/p&gt;
 &lt;/li&gt;
 &lt;li&gt;
  &lt;h3&gt;Language/Profanity Filters&lt;/h3&gt;
  &lt;p&gt;Ya, some of us are still old fashioned like that.  This would be especially appreciated in family and faith oriented blogs.&lt;/p&gt;
 &lt;/li&gt;
 &lt;li&gt;
  &lt;h3&gt;WYSIWYG Editor&lt;/h3&gt;
  &lt;p&gt;Personally, I hate them - but the fact is, WYSIWYG editors are now a consumer expectation.  Given the crowd that tends to follow my articles, this blog would probably benefit a lot less from this than a less code-savvy user base.&lt;/p&gt;
 &lt;/li&gt;
 &lt;li&gt;
  &lt;h3&gt;Private Comments to Authors&lt;/h3&gt;
  &lt;p&gt;I'll admit that from here on out I'm probably going above and beyond what I'd consider "minimum requirements."  However, being able to send private comments to the author would be a handy feature.  For one, it would be a safe and convenient way to share personal contact information.&lt;/p&gt;
 &lt;/li&gt;
 &lt;li&gt;
  &lt;h3&gt;Spell Check&lt;/h3&gt;
  &lt;p&gt;Since I use Firefox, I simply use the built in spell checker, but this would be helpful for visitors using other browsers.  This is another example of something Digg did right...&lt;/p&gt;
 &lt;/li&gt;
 &lt;li&gt;
  &lt;h3&gt;Arbitrary Thread Locks&lt;/h3&gt;
  &lt;p&gt;The author of a blog should be able to enable or disable comments on a post-by-post basis.  This disable feature should have the option to actually hide all the comments, or simply disallow additional comments.&lt;/p&gt;
 &lt;/li&gt;
 &lt;li&gt;
  &lt;h3&gt;Statistics&lt;/h3&gt;
  &lt;p&gt;This is probably the least crucial of all my wants, but it would be nice to see some overall statistics (e.g., average comments per post, post with most comments, etc...).&lt;/p&gt;
 &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Well that's it for my list.  Please feel free to add any additional ideas in the comments!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1078898499337496912-3309892403124930267?l=blog.jeremymartin.name' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jeremymartin.name/feeds/3309892403124930267/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1078898499337496912&amp;postID=3309892403124930267' title='27 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/3309892403124930267'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/3309892403124930267'/><link rel='alternate' type='text/html' href='http://blog.jeremymartin.name/2008/05/how-to-fix-blogger-comment-system.html' title='How to Fix the Blogger Comment System'/><author><name>Jeremy Martin</name><uri>http://www.blogger.com/profile/03514319709844297772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>27</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1078898499337496912.post-8450974354853085091</id><published>2008-05-05T12:30:00.000-07:00</published><updated>2008-05-05T12:48:39.860-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='jQuery'/><title type='text'>jQuery UI 1.5b4 Released</title><content type='html'>&lt;p&gt;&lt;a href="http://paulbakaus.com/" target="new"&gt;Paul Bakaus&lt;/a&gt; and the &lt;a href="http://ui.jquery.com/about" target="new"&gt;jQuery UI team &lt;/a&gt;have just released jQuery UI 1.5b4 - the last scheduled beta version before a release candidate.  Along with the new beta version, the &lt;a href="http://jquery.com/blog/2008/05/05/jquery-ui-15b4-featuring-effects-and-a-new-home/" target="new"&gt;jQuery UI homepage&lt;/a&gt; has been given a major overhaul.  While parts of the site are still under construction, it does include several functional improvements, such as a &lt;a href="http://ui.jquery.com/download_builder/" target="new"&gt;download builder&lt;/a&gt; and an improved &lt;a href="http://ui.jquery.com/demos" target="new"&gt;demo showcase&lt;/a&gt;.  So head on over and check it out!&lt;/p&gt;

&lt;p&gt;Happy Cinco de Mayo!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1078898499337496912-8450974354853085091?l=blog.jeremymartin.name' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jeremymartin.name/feeds/8450974354853085091/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1078898499337496912&amp;postID=8450974354853085091' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/8450974354853085091'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/8450974354853085091'/><link rel='alternate' type='text/html' href='http://blog.jeremymartin.name/2008/05/jquery-ui-15b4-released.html' title='jQuery UI 1.5b4 Released'/><author><name>Jeremy Martin</name><uri>http://www.blogger.com/profile/03514319709844297772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1078898499337496912.post-5605712467992038512</id><published>2008-05-01T10:47:00.000-07:00</published><updated>2008-05-01T10:53:24.034-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='PHP'/><title type='text'>Why PHP and JavaScript IDE's Suck</title><content type='html'>&lt;p&gt;Few things fire up an engineer faster than over generalizations, criticizing a favorite language, or attacking their favorite IDE.  So I'm off to a good start.  Oh ya, my mom hates that word too (sorry Mom)!&lt;/p&gt;

&lt;p&gt;However, interestingly enough, this fact (just concede for now) is not the fault of the given language, or even the IDE developers.  So who's fault is it?  In truth, no ones.  It's really more of a bi-product of these languages themselves (and as we'll see, many other languages (such as Perl) could be thrown into this bunch as well).  In fact, the same IDE, such as Eclipse, can be outstanding with a language like Java, yet be rather disappointing when it comes to PHP.&lt;/p&gt;

&lt;p&gt;So before we go any further, I need to lay out a tighter definition for "suck".  I'll admit that it's too broad a stroke, albeit attention getting.  If I had to pick one single feature that makes or breaks an IDE for me, it would be autocomplete (or Intellisense for you Visual Studio people).  The frameworks and libraries that we use today are simply too big to try and remember every single class/object member, and it's just too slow to go sifting through the documentation every two minutes.  Nothing speeds up my productivity like being able to press &lt;i&gt;Ctrl + Space&lt;/i&gt; and voila - there are my options.  Therefore, to me, and for the purposes of this discussion, any IDE that doesn't have autocomplete that's up to snuff, sucks.&lt;/p&gt;

&lt;p&gt;Thus far, the languages that I've interacted with the most are Java, PHP, C#, C++, JavaScript, and I've dabbled with Object Pascal.  I'd consider myself a jack-of-some, master-of-none.  In the bizarre scenario where I had to put each of these languages into one of two buckets at gun point (me, not the buckets), I would divide them based on this single comparison: strongly-typed versus loosely-typed.&lt;/p&gt;

&lt;p&gt;Interestingly enough, if I compared them based on their respective "IDE suckiness", they'd end up in the same buckets.  Why is that?  Well, as I've already implied, &lt;i&gt;there's a strong correlation between how a language is typed, and how effectively an IDE can offer suggestions from a given context&lt;/i&gt;.  In contrast to a &lt;a href="http://blog.jeremymartin.name/2008/03/understanding-loose-typing-in.html" title="Understanding Loose Typing in JavaScript"&gt;loosely typed&lt;/a&gt; language, a strongly typed language can make some guarantees about what a variable holds.&lt;/p&gt;

&lt;p&gt;For example, if I'm working on a Java application in Eclipse, I can use autocomplete to inspect the members of my current object, like this:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://jmar777.googlecode.com/svn/trunk/images/IDE_Eclipse.png" alt="Eclipse Screenshot" class="no-border" /&gt;&lt;/p&gt;

&lt;p&gt;Most conveniently, all of my autocomplete options are relevant to my &lt;span class="inline_code"&gt;Person&lt;/span&gt; object.  Eclipse can do this because in Java, once I declare &lt;span class="inline_code"&gt;jMar&lt;/span&gt; as a &lt;span class="inline_code"&gt;Person&lt;/span&gt;, it now has a guarantee that &lt;span class="inline_code"&gt;jMar&lt;/span&gt; is and always will be a &lt;span class="inline_code"&gt;Person&lt;/span&gt;.  This guarantee holds true for other strongly typed languages as well, which provides their respective IDE's with the same promise.&lt;/p&gt;

&lt;p&gt;Now let's say I'm working on a PHP application in Dreamweaver.  If I reproduce the equivilent Java code from above, my "autocomplete" options are really just a list of every function defined in the PHP5 documentation.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://jmar777.googlecode.com/svn/trunk/images/IDE_Dreamweaver.png" alt="Dreamweaver Screenshot" class="no-border" /&gt;&lt;/p&gt;

&lt;p&gt;Slightly more helpful than nothing, but it's far short of I had before - not to mention that this gives me no insight into the members of my &lt;span class="inline_code"&gt;Person&lt;/span&gt; class.  But don't hate Dreamweaver - what else can it do?  Remember - when you're coding in PHP, you're not making any guarantees as to what a variable holds.&lt;/p&gt;

&lt;p&gt;Consider the following perfectly legal PHP code:&lt;/p&gt;

&lt;pre name="code" class="php"&gt;
class FirstClass {
 ...
}

class SecondClass {
 ...
}

$foo = new FirstClass(); // $foo is now a FirstClass
$foo = new SecondClass(); // $foo is now a SecondClass
$foo = &amp;#34;bar&amp;#34;; // $foo is now a string
$foo = true; // $foo is now a boolean
$foo = 777; // $foo is now an int
&lt;/pre&gt;

&lt;p&gt;No wonder the autocomplete isn't much help.  And this is the exact same scenario for JavaScript, Perl, and other loosely typed languages.&lt;/p&gt;

&lt;p&gt;I know I've personally been frustrated on numerous occasions with the apparent "lack of effort" being given to autocomplete with regards to these widely used languages; however, after pondering some of the fundamental obsticles that the IDE developers are facing, I can understand how the feature set is impacted by the target language.  I suppose an article can only be so valuable without offering some sort of a solution, but just consider this a "state of affairs" on the IDE world, and thanks for reading!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1078898499337496912-5605712467992038512?l=blog.jeremymartin.name' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jeremymartin.name/feeds/5605712467992038512/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1078898499337496912&amp;postID=5605712467992038512' title='21 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/5605712467992038512'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/5605712467992038512'/><link rel='alternate' type='text/html' href='http://blog.jeremymartin.name/2008/05/why-php-and-javascript-ides-suck.html' title='Why PHP and JavaScript IDE&apos;s Suck'/><author><name>Jeremy Martin</name><uri>http://www.blogger.com/profile/03514319709844297772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>21</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1078898499337496912.post-7695968179342767465</id><published>2008-04-22T07:05:00.000-07:00</published><updated>2008-04-22T07:28:57.730-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PHP'/><category scheme='http://www.blogger.com/atom/ns#' term='Guest Author'/><title type='text'>Know Your Environment: PHP Server Module Reporter</title><content type='html'>&lt;div class="guest_author_intro"&gt;
 This post was authored by &lt;a href="http://www.davidwalsh.name" title="David Walsh's Blog" target="new"&gt;David Walsh&lt;/a&gt;.  To learn more about David, &lt;a href="#bio-david"&gt;click here&lt;/a&gt;.
&lt;/div&gt;

&lt;p&gt;One of the unfortunate parts on my job is that I rarely get a say in the customer's hosting environment.  We don't host our customers' sites so I'm usually at the mercy of whichever hosting provider the customer has contracted with.  We usually try to steer our customer toward our preferred host, but most of the time the customer is reluctant to switch because they fear email issues and change in general.&lt;/p&gt;

&lt;p&gt;Knowing the hosting environment's limitations before we begin to develop the website is a must.  Imagine creating a great website and running into issues later on because the shared hosting server doesn't have a given extension installed.  A nightmare!&lt;/p&gt;

&lt;p&gt;I've created a basic PHP script that I simply FTP to the server and use to evaluate extensions on the server.  I simply supply the extensions I require and the script does the rest of the work.&lt;/p&gt;


&lt;pre name="code" class="php"&gt;
&amp;#60;?php
 /* set required extensions */
 $my_required_extensions = array(
  &amp;#39;gd&amp;#39;,  //graphics library
  &amp;#39;xml&amp;#39;,  //xml
  &amp;#39;mysql&amp;#39;, //database
  &amp;#39;curl&amp;#39;,  //networking
  &amp;#39;openssl&amp;#39;, //site will need SSL
  &amp;#39;pecl&amp;#39;  //pear
 );
 natcasesort($my_required_extensions);
 
 //get loaded modules
 $loaded_extensions = get_loaded_extensions();
?&amp;#62;

&amp;#60;!DOCTYPE html PUBLIC &amp;#34;-//W3C//DTD XHTML 1.0 Strict//EN&amp;#34; &amp;#34;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&amp;#34;&amp;#62;
&amp;#60;html xmlns=&amp;#34;http://www.w3.org/1999/xhtml&amp;#34; xml:lang=&amp;#34;en&amp;#34; lang=&amp;#34;en&amp;#34;&amp;#62;
&amp;#60;head&amp;#62;
 &amp;#60;title&amp;#62;&amp;#60;?php echo $source_article; ?&amp;#62; Example&amp;#60;/title&amp;#62;
 &amp;#60;meta name=&amp;#34;description&amp;#34; value=&amp;#34;&amp;#60;?php echo htmlentities($meta_description); ?&amp;#62;&amp;#34; /&amp;#62;
 &amp;#60;style type=&amp;#34;text/css&amp;#34;&amp;#62;
  body  { font-size:12px; }
  h2   { border-bottom:1px solid #ccc; font-weight:normal; font-size:18px; margin-bottom:5px; padding-bottom:2px; }
  p   { line-height:20px; margin-top:0; }
  .found  { background:lightgreen; padding:5px 10px; margin:0 0 10px 0; }
  .miss  { background:pink; padding:5px 10px; margin:0 0 10px 0; }
  .extra  { background:lightblue; padding:5px 10px; margin:0 0 10px 0; }
 &amp;#60;/style&amp;#62;
&amp;#60;/head&amp;#62;
&amp;#60;body&amp;#62;

&amp;#60;h1&amp;#62;&amp;#60;?php echo $_SERVER[&amp;#39;HTTP_HOST&amp;#39;]; ?&amp;#62;&amp;#60;/h1&amp;#62;

&amp;#60;h2&amp;#62;General Information&amp;#60;/h2&amp;#62;
&amp;#60;p&amp;#62;
 &amp;#60;strong&amp;#62;Server Software:&amp;#60;/strong&amp;#62;  &amp;#60;?php echo $_SERVER[&amp;#39;SERVER_SOFTWARE&amp;#39;]; ?&amp;#62;&amp;#60;br /&amp;#62;
 &amp;#60;strong&amp;#62;Document Root:&amp;#60;/strong&amp;#62; &amp;#60;?php echo $_SERVER[&amp;#39;DOCUMENT_ROOT&amp;#39;]; ?&amp;#62;&amp;#60;br /&amp;#62;
 &amp;#60;strong&amp;#62;PHP Version:&amp;#60;/strong&amp;#62; &amp;#60;?php echo phpversion(); ?&amp;#62;
&amp;#60;/p&amp;#62;

&amp;#60;h2&amp;#62;Extension Check&amp;#60;/h2&amp;#62;
&amp;#60;?php 
 /* print out */
 //analyze results
 foreach($my_required_extensions as $ext)
 {
  if(in_array($ext,$loaded_extensions))
  {
   $matches[] = strtolower($ext);
  }
  else
  {
   $missings[] = strtolower($ext);
  }
  unset($loaded_extensions[$ext]);
 }
 //print out results
 natcasesort($matches); natcasesort($missings); natcasesort($loaded_extensions);
 foreach($matches as $match) { echo &amp;#39;&amp;#60;div class=&amp;#34;found&amp;#34;&amp;#62;&amp;#60;strong&amp;#62;&amp;#39;,$match,&amp;#39;&amp;#60;/strong&amp;#62; found!&amp;#60;/div&amp;#62;&amp;#39;; }
 foreach($missings as $miss) { echo &amp;#39;&amp;#60;div class=&amp;#34;miss&amp;#34;&amp;#62;&amp;#60;strong&amp;#62;&amp;#39;,$miss,&amp;#39;&amp;#60;/strong&amp;#62; missing!&amp;#60;/div&amp;#62;&amp;#39;; }
 foreach($loaded_extensions as $e) { if(!in_array($e,$matches) &amp;#38;&amp;#38; !in_array($e,$missings)) { echo &amp;#39;&amp;#60;div class=&amp;#34;extra&amp;#34;&amp;#62;&amp;#60;strong&amp;#62;&amp;#39;,$e,&amp;#39;&amp;#60;/strong&amp;#62; is available.&amp;#60;/div&amp;#62;&amp;#39;; } }
?&amp;#62;&amp;#60;br /&amp;#62;

&amp;#60;/body&amp;#62;
&amp;#60;/html&amp;#62;
&lt;/pre&gt;

&lt;p&gt;The output looks as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://jmar777.googlecode.com/svn/trunk/images/walsh/modules.png" target="new"&gt;&lt;img class="no-border" src="http://jmar777.googlecode.com/svn/trunk/images/walsh/modules_small.png" alt="Extension Evaluator Screenshot"&gt;&lt;/a&gt;&lt;br/&gt;
(click to enlarge)&lt;/p&gt;

&lt;p&gt;If I run into the situation where a needed extension isn't there, I must decide whether to push for the customer to switch hosts or adjust the way I code the website.  You'll also want to  keep a copy of this on hand so that you have proof when the host changes the server and causes issues with the website.  Happy coding!&lt;/p&gt;

&lt;a name="bio-david" id="bio-david"&gt;&lt;/a&gt;

&lt;div class="guest_author_bio"&gt;
 &lt;p&gt;&lt;img src="http://jmar777.googlecode.com/svn/trunk/images/walsh/david-walsh.gif" alt="David Walsh." /&gt;&lt;a href="http://www.davidwalsh.name" target="new"&gt;David Walsh&lt;/a&gt; is a Senior Web Developer residing in Madison, WI.  He spends most of his day getting a monitor tan coding PHP, CSS, MooTools, and XHTML.  When not tinkering with the newest version of &lt;a href="http://www.mootools.net/" target="new"&gt;Moo&lt;/a&gt;, David uses soccer, Rock Band, and movies to dull his coding pains.&lt;/p&gt;
 &lt;div style="clear:both;"&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1078898499337496912-7695968179342767465?l=blog.jeremymartin.name' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jeremymartin.name/feeds/7695968179342767465/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1078898499337496912&amp;postID=7695968179342767465' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/7695968179342767465'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/7695968179342767465'/><link rel='alternate' type='text/html' href='http://blog.jeremymartin.name/2008/04/know-your-environment-php-server-module.html' title='Know Your Environment: PHP Server Module Reporter'/><author><name>Jeremy Martin</name><uri>http://www.blogger.com/profile/03514319709844297772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1078898499337496912.post-2673343480828503755</id><published>2008-04-18T06:54:00.000-07:00</published><updated>2008-04-21T09:28:37.239-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><title type='text'>Add Hover Class to Anything in jQuery</title><content type='html'>&lt;p&gt;Well I've been feeling a little guilty for the relative sparsity of my posts lately (not that I don't have a good excuse or two), but I wanted to at least get on here and share a quick little tip.&lt;/p&gt;

&lt;p&gt;One of the most fundamental "effects" employed by CSS designers is that of indicating when an anchor tag is being "hovered".  Virtually every CSS file you encounter will contain something like the following:&lt;/p&gt;

&lt;pre name="code" class="css"&gt;
a:link {
 /* default styles for anchors */
}

a:hover {
 /* styles for hovered anchors */
}
&lt;/pre&gt;

&lt;p&gt;Often times, however, this same effect is desirable for non-anchor elements as well.  For example, in my applications, I like to visually indicate anything that can be the target of an onclick event - and practically speaking, that's not always an anchor.  The problem is that &lt;span class="inline_code"&gt;:hover&lt;/span&gt; is not a reliable cross-browser pseudo-selector on non-anchor elements.  Can anyone guess which cl&lt;strong&gt;IE&lt;/strong&gt;nt I'm talking about?&lt;/p&gt;

&lt;p&gt;Well fret not, cause we have JavaScript to the rescue.  In this particular example, as usual, I'm using jQuery to make life easy.  Since we can't rely on &lt;span class="inline_code"&gt;:hover&lt;/span&gt;, we're going to dynamically add a class of &lt;span class="inline_code"&gt;hover&lt;/span&gt; via JavaScript.  The code to do this is remarkably simple:&lt;/p&gt;

&lt;pre name="code" class="js"&gt;
$(&amp;#39;*&amp;#39;).hover(
 function() {
  $(this).addClass(&amp;#39;hover&amp;#39;);
 },
 function() {
  $(this).removeClass(&amp;#39;hover&amp;#39;);
 }
);
&lt;/pre&gt;

&lt;p&gt;Now let's say you want to style a &lt;span class="inline_code"&gt;div&lt;/span&gt; with class &lt;span class="inline_code"&gt;iHoverable&lt;/span&gt; differently when it's being hovered.  You can simply add the following rule to your style sheet:&lt;/p&gt;

&lt;pre name="code" class="css"&gt;
.iHoverable {
 /* normal styles for this element */
}
.iHoverable.hover {
 /* styles for hover effect */
}
&lt;/pre&gt;

&lt;p&gt;That's almost it - just a quick note from a practicality standpoint.  I don't really recommend using &lt;span class="inline_code"&gt;$(&amp;#39;*&amp;#39;).hover(...)&lt;/span&gt; from the code above.  If you already know that you only need to style hovers for elements of class &lt;span class="inline_code"&gt;iHoverable&lt;/span&gt;, then it would be more efficient to simply write &lt;span class="inline_code"&gt;$(&amp;#39;.iHoverable&amp;#39;).hover(...)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Kapeesh?  Ok, now that's it.&lt;/p&gt;

&lt;div class="update"&gt;
  &lt;h5&gt;OOPS!&lt;/h5&gt;
  &lt;p&gt;It has come to my attention that this post is remarkably similar to a &lt;a href="http://www.learningjquery.com/2007/02/quick-tip-set-hover-class-for-anything"&gt;previous post&lt;/a&gt; by &lt;a href="http://www.englishrules.com/"&gt;Karl Swedburg&lt;/a&gt; from over a year ago.  My bad!&lt;/p&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1078898499337496912-2673343480828503755?l=blog.jeremymartin.name' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jeremymartin.name/feeds/2673343480828503755/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1078898499337496912&amp;postID=2673343480828503755' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/2673343480828503755'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/2673343480828503755'/><link rel='alternate' type='text/html' href='http://blog.jeremymartin.name/2008/04/add-hover-class-to-anything-in-jquery.html' title='Add Hover Class to Anything in jQuery'/><author><name>Jeremy Martin</name><uri>http://www.blogger.com/profile/03514319709844297772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1078898499337496912.post-2111781087252489965</id><published>2008-04-17T11:13:00.000-07:00</published><updated>2008-04-17T11:18:44.371-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PHP'/><title type='text'>Load Your Static Content the Dynamic Way</title><content type='html'>&lt;p&gt;&lt;a href="http://davidwalsh.name"&gt;David Walsh&lt;/a&gt; was kind enough to let me guest author an article on his blog.  &lt;a href="http://davidwalsh.name/load-static-content-dynamic"&gt;Check it out!&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1078898499337496912-2111781087252489965?l=blog.jeremymartin.name' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jeremymartin.name/feeds/2111781087252489965/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1078898499337496912&amp;postID=2111781087252489965' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/2111781087252489965'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/2111781087252489965'/><link rel='alternate' type='text/html' href='http://blog.jeremymartin.name/2008/04/load-your-static-content-dynamic-way.html' title='Load Your Static Content the Dynamic Way'/><author><name>Jeremy Martin</name><uri>http://www.blogger.com/profile/03514319709844297772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1078898499337496912.post-4112664421175314617</id><published>2008-04-12T11:01:00.000-07:00</published><updated>2008-05-29T14:13:11.586-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Kwicks'/><category scheme='http://www.blogger.com/atom/ns#' term='jQuery'/><title type='text'>Introducing: Kwicks for jQuery</title><content type='html'>&lt;p&gt;Well despite the underwhelming response I got from my teaser post earlier in the week, I went ahead and wrapped things up.  For those of you jQuery fans who have been ashamedly drooling over the perfectly simple Kwicks effect for &lt;a href="http://www.mootools.net" title="Mootools Homepage"&gt;Mootools&lt;/a&gt;, now you can have it too.&lt;/p&gt;
&lt;p&gt;The Kwicks for jQuery plugin, documentation, and examples can be found at the &lt;a href="http://www.jeremymartin.name/projects.php?project=kwicks" title="Kwicks for jQuery Homepage"&gt;Kwicks for jQuery Homepage&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So far I've only been able to test it in IE6+, FF2+, Safari 3 for Windows, and Opera 9.  If you encounter any issues let me know!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1078898499337496912-4112664421175314617?l=blog.jeremymartin.name' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jeremymartin.name/feeds/4112664421175314617/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1078898499337496912&amp;postID=4112664421175314617' title='67 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/4112664421175314617'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/4112664421175314617'/><link rel='alternate' type='text/html' href='http://blog.jeremymartin.name/2008/04/introducing-kwicks-for-jquery.html' title='Introducing: Kwicks for jQuery'/><author><name>Jeremy Martin</name><uri>http://www.blogger.com/profile/03514319709844297772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>67</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1078898499337496912.post-5856920956848305437</id><published>2008-04-08T06:22:00.000-07:00</published><updated>2008-04-08T06:34:00.090-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Kwicks'/><category scheme='http://www.blogger.com/atom/ns#' term='jQuery'/><title type='text'>Spoiler Alert!</title><content type='html'>&lt;p&gt;So I might have over dramatized this post a little - but I wanted to let you all know what I've been working on the last couple days...&lt;/p&gt;

&lt;p&gt;&lt;img src="http://jmar777.googlecode.com/svn/trunk/images/kwicks_teaser.jpg" alt="Kwicks Teaser" class="no-border" /&gt;&lt;/p&gt;

&lt;p&gt;Ya... totally awesome.  I really just wanted to post this so that I could hear any special requests while I wrap things up.  I really love the effect of this menu (see the &lt;a href="http://mootools.net/" title="Mootools Home Page"&gt;Mootools&lt;/a&gt; home page), but I haven't actually used the Mootools original before.  Therefore if there are any annoyances - I don't know what they are.  The options that it currently supports are maxWidth, spacing, duration, and easing.  If there's anything else you'd like to have control over, let me know now!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1078898499337496912-5856920956848305437?l=blog.jeremymartin.name' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jeremymartin.name/feeds/5856920956848305437/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1078898499337496912&amp;postID=5856920956848305437' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/5856920956848305437'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/5856920956848305437'/><link rel='alternate' type='text/html' href='http://blog.jeremymartin.name/2008/04/spoiler-alert.html' title='Spoiler Alert!'/><author><name>Jeremy Martin</name><uri>http://www.blogger.com/profile/03514319709844297772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1078898499337496912.post-9011558840509441400</id><published>2008-04-03T10:39:00.000-07:00</published><updated>2008-04-04T11:25:13.622-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><title type='text'>Big Regex Improvements for Firefox 3 Beta 5</title><content type='html'>&lt;p&gt;Having just posted my latest project, &lt;a href="http://www.jeremymartin.name/projects.php?project=asciible" title="Asciible"&gt;Asciible&lt;/a&gt;, that relies heavily (well, entirely) on client-side regular expressions, I've been paying closer attention to efficiency concerns.  I don't know if I'd really consider myself to be a Firefox "fan boy", but it is my browser of choice, and I have to admit that I was surprised to find that IE7 was kicking FF2's butt when it came to executing &lt;span class="inline_code"&gt;String.replace()&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;To give you a real world context for my tests, Asciible simply searches through a text input and replaces special characters with their ASCII equivalents.  Even all the custom options rely solely on simple &lt;span class="inline_code"&gt;String.replace()&lt;/span&gt;'s.  So in fairness, be aware that this limited test does not represent an overall analysis of the regular expression engine.  With that said, in this limited context IE was taking about 10% of the time it was taking Firefox to complete.  I was even able to achieve nearly the same efficiency in FF2 by using a simple for loop and a character hash table - yuck.&lt;/p&gt;

&lt;p&gt;After noticing this, I went and downloaded Firefox 3, Beta 4 and ran my tests again.  I was disappointed to find only marginal improvements.&lt;/p&gt;

&lt;p&gt;So time advances until earlier today when I was taking a look at the release notes for &lt;a href="http://www.mozilla.com/en-US/firefox/3.0b5/releasenotes/#performance" alt="Firefox 3 Beta 5 Release Notes"&gt;Firefox 3 Beta 5&lt;/a&gt;, and I couldn't help but notice they were touting some major performance improvements - specifically to the JavaScript engine.  So with curiosity in hand I downloaded, installed, and ran my tests again.  To spare you the suspense - no, Firefox did not put IE to shame, and in truth it was still the slower of the two.  However it did show BIG improvements - and I'm happy to see that the regular expression engine has been given some serious attention.  All in all, FF3 Beta 5 was completing the test in less than half the time it was taking FF2.  For visualization purposes:&lt;/p&gt;

&lt;p&gt;&lt;img class="no-border" src="http://jmar777.googlecode.com/svn/trunk/images/FF3B5_regex.png" alt="String.replace() comparison for IE7, FF2, and FF3 Beta 5" /&gt;&lt;/p&gt;

&lt;p&gt;This is good news, especially since FF3 is still in beta.  There's no guarantee that there will be further improvements in the final release, but the optimizations thus far are already outstanding, and certainly enough to leave me with my fingers crossed.&lt;/p&gt;

&lt;div class="thanks_reddit"&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1078898499337496912-9011558840509441400?l=blog.jeremymartin.name' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jeremymartin.name/feeds/9011558840509441400/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1078898499337496912&amp;postID=9011558840509441400' title='17 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/9011558840509441400'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/9011558840509441400'/><link rel='alternate' type='text/html' href='http://blog.jeremymartin.name/2008/04/big-regex-improvements-for-firefox-3.html' title='Big Regex Improvements for Firefox 3 Beta 5'/><author><name>Jeremy Martin</name><uri>http://www.blogger.com/profile/03514319709844297772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>17</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1078898499337496912.post-7929420226696833591</id><published>2008-04-03T05:52:00.000-07:00</published><updated>2008-04-03T06:03:12.515-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Misc'/><title type='text'>The Slashdot Effect</title><content type='html'>&lt;p&gt;I suppose this just puts me in a long list of gratefuls to the slashdot community - but I wanted to give an overdue "thank you" to everyone who voted and put my &lt;a href="http://blog.jeremymartin.name/2008/03/web-20-meet-javascript-20.html" title="Web 2.0, Meet JavaScript 2.0"&gt;Web 2.0, Meet JavaScript 2.0&lt;/a&gt; article on the front page.  Not that you haven't seen 100 such graphs before, but just in case you wanted to see how you utterly destroyed my traffic curve:&lt;/p&gt;

&lt;p&gt;&lt;img class="no-border" src="http://jmar777.googlecode.com/svn/trunk/images/slashdot_effect.png" alt="The Slashdot Effect" /&gt;&lt;/p&gt;

&lt;p&gt;Incidentally, the same article made the front page of Reddit as well.  The amount of traffic from Reddit was approximately 10% of that from Slashdot, but thanks to you Reddit folks none-the-less!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1078898499337496912-7929420226696833591?l=blog.jeremymartin.name' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jeremymartin.name/feeds/7929420226696833591/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1078898499337496912&amp;postID=7929420226696833591' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/7929420226696833591'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/7929420226696833591'/><link rel='alternate' type='text/html' href='http://blog.jeremymartin.name/2008/04/slashdot-effect.html' title='The Slashdot Effect'/><author><name>Jeremy Martin</name><uri>http://www.blogger.com/profile/03514319709844297772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1078898499337496912.post-1502711674061543254</id><published>2008-04-01T13:54:00.000-07:00</published><updated>2008-04-02T06:25:30.966-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Asciible'/><category scheme='http://www.blogger.com/atom/ns#' term='jQuery'/><title type='text'>Introducing: Asciible</title><content type='html'>&lt;p&gt;&lt;a href="http://www.jeremymartin.name/projects.php?project=asciible" title="Asciible"&gt;&lt;img src="http://jmar777.googlecode.com/svn/trunk/images/asciible.gif" alt="Asciible" class="no-border" style="float:left;padding:0 20px 0 0;" /&gt;&lt;/a&gt;Well, I've been silent for a little while - but I haven't been lazy!  I've been a little slammed for time as of late, but I do have something new to to introduce: &lt;a href="http://www.jeremymartin.name/projects.php?project=asciible" title="Asciible"&gt;Asciible&lt;/a&gt;.  As far as naming goes, Asciible barely edged out "Ascii Jeaves" - but it's never too late to go back...&lt;/p&gt;

&lt;p&gt;In a nutshell, Asciible does all your ascii encoding for you.  This obviously isn't the first utility to offer this service, but I have tried to make it the fastest and most flexible.  &lt;a href="http://www.jeremymartin.name/projects.php?project=asciible"&gt;Give it a whirl&lt;/a&gt; and let me know what you think!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1078898499337496912-1502711674061543254?l=blog.jeremymartin.name' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jeremymartin.name/feeds/1502711674061543254/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1078898499337496912&amp;postID=1502711674061543254' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/1502711674061543254'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/1502711674061543254'/><link rel='alternate' type='text/html' href='http://blog.jeremymartin.name/2008/04/introducing-asciible.html' title='Introducing: Asciible'/><author><name>Jeremy Martin</name><uri>http://www.blogger.com/profile/03514319709844297772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1078898499337496912.post-2918724552080353942</id><published>2008-03-18T10:39:00.000-07:00</published><updated>2008-03-18T10:59:24.743-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><title type='text'>Web 2.0, Meet JavaScript 2.0</title><content type='html'>&lt;p&gt;Well I suppose it's an undeniable fact about us programmer-types - every now and then we just can't help but get excited about something really nerdy.  For me right now, that is definitely JavaScript 2.0.  I was just taking a look at the proposed specifications and I am really, truly excited about what we have coming.&lt;/p&gt;

&lt;p&gt;I suppose it's important to note that these new features are tentative.  The specifications documentation for JavaScript 2.0, ECMAScript Edition 4, is currently being developed by &lt;a href="http://www.ecma-international.org/memento/TC39.htm" target="new"&gt;TC39&lt;/a&gt;.  Although it is still a work in progress, an overview of what has currently been proposed can be found &lt;a href="http://www.ecmascript.org/es4/spec/overview.pdf" target="new"&gt;here&lt;/a&gt; (PDF).  As the team expects to have completed the specifications by late fall of this year, we can expect that most of these awesome improvements will remain in the final version.&lt;/p&gt;

&lt;p&gt;So without further delay, here's just a few of the many, many upgrades coming JavaScript 2.0's way:&lt;/p&gt;

&lt;h5&gt;OOP!&lt;/h5&gt;
&lt;p&gt;Had to start with this one - it's so big it had to be first.  Introducing actual classes and interfaces into the language is likely the most radical change that will come with JavaScript 2.0.  Technically speaking, OOP will be nothing new for JavaScript.  JavaScript already has objects and even offers full support for inheritance through the prototype chain - however, prototypal inheritance in JavaScript is tricky business and can often produce unexpected results (especially for those accustomed to classical inheritance in languages such as Java and C#).&lt;/p&gt;

&lt;p&gt;Not only is JavaScript introducing classes into the language, is is also doing away with primitives altogether.  &lt;i&gt;Null&lt;/i&gt; and &lt;i&gt;undefined&lt;/i&gt; will be the only not true objects in JavaScript 2.0.  Duly, classes such as boolean and string will provide wrapper classes for the sake of backwards compatibility.&lt;/p&gt;

&lt;p&gt;As far as creating and instantiating a basic "class" goes, the process will be quite similar to using a constructor function, as in earlier versions of JavaScript.  Consider the following examples:&lt;/p&gt;

&lt;pre name="code" class="js"&gt;
/* JavaScript 1.x &amp;quot;Class&amp;quot; Definition*/
function Foo() {
 this.a = &amp;quot;a&amp;quot;;
 this.b = &amp;quot;b&amp;quot;;
}
var myFoo = new Foo(); // class instantiation

/* JavaScript 2.0 Class Definition */
class Bar {
 this.a = &amp;quot;a&amp;quot;;
 this.b = &amp;quot;b&amp;quot;;
}
var myBar = new Bar(); // class instantiation
&lt;/pre&gt;

&lt;p&gt;That alone hardy seems worth the overhaul, but classes will provide far more flexibility through its many designators and directives (final, dynamic, extends, implements, etc.).  Also note that constructor functions can be changed, whereas classes will be bound as constants, and therefore cannot be changed.&lt;/p&gt;

&lt;p&gt;Object Oriented Programming has done to programming what relational databases did to persistence - it has dominated.  I can't think of a single thing that I would rather see in JavaScript 2.0 than exactly this.&lt;/p&gt;

&lt;h5&gt;Compile Time Type Checking&lt;/h5&gt;
&lt;p&gt;JavaScript 2.0 components can request to be compiled in &lt;i&gt;strict&lt;/i&gt; mode.  This will test the integrity of several key aspects &lt;i&gt;before&lt;/i&gt; execution.  A partial list of these checks includes:
&lt;ul&gt;
 &lt;li&gt;Static type checking&lt;/li&gt;
 &lt;li&gt;Verification that referenced names are known&lt;/li&gt;
 &lt;li&gt;Checks for illegal assignments to &lt;i&gt;constants&lt;/i&gt;&lt;/li&gt;
 &lt;li&gt;Insures that comparisons are only made between valid types&lt;/li&gt;
&lt;/ul&gt;&lt;/p&gt;

&lt;h5&gt;Did I Say Constants?&lt;/h5&gt;
&lt;p&gt;I sure did.  For such an obvious directive, constants have been a long time in coming.  Previously JavaScript developers have had to use naming conventions to protect their constants, but that is no longer the case in JavaScript 2.0.&lt;/p&gt;

&lt;pre name="code" class="js"&gt;
/* JavaScript 1.x constant */
var FOO = &amp;#39;bar&amp;#39;;  // look, I&amp;#39;m all upper cases, so pretty please don&amp;#39;t change me

/* JavaScript 2.0 constant */
const FOO = &amp;#39;bar&amp;#39;; // go ahead, try me...
&lt;/pre&gt;

&lt;p&gt;It may take some time to realize some of the side effects of this change, however, since the constant directive will now be applied to some of the existing core JavaScript objects (such as the pointer to an object's prototype).&lt;/p&gt;

&lt;h5&gt;Operator Overloading&lt;/h5&gt;
&lt;p&gt;&lt;i&gt;Cause I am, whatever you say I am, if I wasn't, then why would I...&lt;/i&gt; never mind.  Misuse it, abuse it, do whatever you want with it.  Operators are now whatever you want.&lt;/p&gt;

&lt;h5&gt;Not Null ("!") Operator&lt;/h5&gt;
&lt;p&gt;Nullability is a concept that is familiar to anyone who's worked with databases, hibernate annotations in Java, or a whole host of other technologies.  In short, it allows you to specify whether an entity can be null or not.  Consider the following example:&lt;/p&gt;

&lt;pre name="code" class="js"&gt;
class Person! {
 ...
}
var x = new Person();

var x = null; // throws error
&lt;/pre&gt;

&lt;p&gt;I'll be honest and admit that I wasn't sure if the error gets thrown on assignment, or when you attempt to read.  For now, examples in the documentation are sparse, but either way this will be a handy feature.  The mechanism that makes this new operator possible is &lt;i&gt;union types&lt;/i&gt; (also new).  I won't be delving into those in this article, but they would definitely be worth reading up on at the original source.&lt;/p&gt;

&lt;h5&gt;Real Namespaces&lt;/h5&gt;
&lt;p&gt;JavaScript developers have long been implementing namespaces by stuffing everything into a single global object.  While this is not a bad convention (and it's much better than cluttering the global namespace), the reality is that it abuses the purpose of objects for the sake of simulating pseudo-namespaces.  Well, have a guilty conscience no more, because now you have real bonafide namespaces that are actually made for being, well, namespaces.&lt;/p&gt;

&lt;h5&gt;Program Units&lt;/h5&gt;
&lt;p&gt;This is a simple addition, but to me it yields great benefits.  Program units allow you to bundle up "program fragments" that don't need to be loaded until requested.  This ability has all sorts of potential, not excluding bandwidth optimization.&lt;/p&gt;

&lt;p&gt;Perhaps more significant, though, this is also a big step towards providing structured, reusable code libraries.  Since the units that you reference will be loaded at most once, you now have a mechanism for maintaining elegant code libraries.  Consider the following example:&lt;/p&gt;

&lt;pre name="code" class="js"&gt;
use unit Person &amp;quot;http://mysite/library/classes/Person&amp;quot;;
use unit DisplayUtil &amp;quot;http://mysite/library/utils/DisplayUtil&amp;quot;;

var bob = new Person();
document.writeln(DisplayUtil.display(bob));
&lt;/pre&gt;

&lt;p&gt;Even in this short, fanciful example you can see how your code can start to take on a highly organized and logical structure - much like many of the server side languages you may have worked with.  Personally, I think this is one of the strongest improvements found in the specifications.&lt;/p&gt;

&lt;h5&gt;Conclusion&lt;/h5&gt;
&lt;p&gt;Well, needless to say, JavaScript 2.0 is shaping up to be a devastatingly awesome improvement.  The specifications go on for about 40 pages of size 12 font, so I'm not even going to try and provide a complete overview.  But as I've said, everything I've mentioned above can be found in the proposed &lt;a href="http://www.ecmascript.org/es4/spec/overview.pdf" target="new"&gt;language overview&lt;/a&gt; (PDF) - and there's several more goodies to be found in there as well.  Thanks for reading!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1078898499337496912-2918724552080353942?l=blog.jeremymartin.name' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jeremymartin.name/feeds/2918724552080353942/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1078898499337496912&amp;postID=2918724552080353942' title='64 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/2918724552080353942'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/2918724552080353942'/><link rel='alternate' type='text/html' href='http://blog.jeremymartin.name/2008/03/web-20-meet-javascript-20.html' title='Web 2.0, Meet JavaScript 2.0'/><author><name>Jeremy Martin</name><uri>http://www.blogger.com/profile/03514319709844297772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>64</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1078898499337496912.post-5252410867450151227</id><published>2008-03-14T14:16:00.000-07:00</published><updated>2008-03-14T15:19:36.963-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><title type='text'>Understanding Loose Typing in JavaScript</title><content type='html'>&lt;p&gt;For many front end developers, JavaScript was their first taste of a scripting and/or interpretive language. To these developers, the concept and implications of loosely typed variables may be second nature.  However, the explosive growth in the demand for Web 2.0-ish applications has resulted in a growing number of back end developers that have had to dip their feet into pool of client side technologies.  Many of these developers are coming from a background in strongly typed languages, such as C# and Java, and are unfamiliar with both the freedom and the potential pitfalls involved in working with loosely typed variables.&lt;/p&gt;

&lt;p&gt;Since the concept of loose typing is so fundamental to scripting in JavaScript, an understanding of it is essential.  This article is a top level discussion of loose typing in JavaScript.  Since there may be subtle differences in loose typing from language to language, let me constrain this discussion to the context of JavaScript.  OK, let's dig in...&lt;/p&gt;

&lt;h5&gt;What is Loose Typing?&lt;/h5&gt;
&lt;p&gt;Well, this seems like a good place to start.  It is important to understand both what loose typing &lt;i&gt;is&lt;/i&gt;, and what loose typing &lt;i&gt;is not&lt;/i&gt;.  Loose typing means that variables are declared without a type.  This is in contrast to strongly typed languages that require typed declarations.  Consider the following examples:&lt;/p&gt;

&lt;pre name="code" class="js"&gt;
/* JavaScript Example (loose typing) */
var a = 13; // Number declaration
var b = &amp;quot;thirteen&amp;quot;; // String declaration

/* Java Example (strong typing) */
int a = 13; // int declaration
String b = &amp;quot;thirteen&amp;quot;; // String declaration
&lt;/pre&gt;

&lt;p&gt;Notice that in the JavaScript example, both a and b are declared as type var.  Please note, however, that this does &lt;i&gt;not&lt;/i&gt; mean that they do not have a type, or even that they are of type "var". Variables in JavaScript &lt;i&gt;are&lt;/i&gt; typed, but that type is determined internally.  In the above example, var a will be type &lt;span class="inline_code"&gt;Number&lt;/span&gt; and var b will be type &lt;span class="inline_code"&gt;String&lt;/span&gt;.  These are two out of the three primitives in JavaScript, the third being &lt;span class="inline_code"&gt;Boolean&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;JavaScript also has other types beyond primitives.  The type diagram for JavaScript is as follows (as per &lt;a href="http://developer.mozilla.org/en/docs/A_re-introduction_to_JavaScript" target="new"&gt;Mozilla&lt;/a&gt;):&lt;/p&gt;

&lt;p&gt;&lt;img class="no-border" src="http://image.bayimg.com/oajpbaabc.jpg" title="JavaScript Type Diagram" /&gt;&lt;/p&gt;

&lt;p&gt;Ya really - Null and Undefined too.&lt;/p&gt;

&lt;p&gt;Note, however, that this distinction between primitives and objects will be dismissed in JavaScript 2.0.  You can read more about that &lt;a href="http://www.mozilla.org/js/language/js20-2000-07/libraries/types.html" target="new"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h5&gt;Type Coercion&lt;/h5&gt;
&lt;p&gt;Type coercion is a topic that is closely associated with loose typing.  Since data types are managed internally, types are often converted internally as well.  Understanding the rules of type coercion is extremely important.  Consider the following expressions, and make sure you understand them:&lt;/p&gt;

&lt;pre name="code" class="js"&gt;
7 + 7 + 7; // = 21
7 + 7 + &amp;quot;7&amp;quot;; // = 147
&amp;quot;7&amp;quot; + 7 + 7; // = 777
&lt;/pre&gt;

&lt;p&gt;In the examples above, arithmetic is carried out as normal (left to right) until a String is encountered.  From that point forward, all entities are converted to a String and then concatenated.&lt;/p&gt;

&lt;p&gt;Type coercion also occurs when doing comparisons.  You can, however, forbid type coercion by using the === operator.  Consider these examples:&lt;/p&gt;

&lt;pre name="code" class="js"&gt;
1 == true; // = true
1 === true; // = false

7 == &amp;quot;7&amp;quot;; // = true
7 === &amp;quot;7&amp;quot;; // = false;
&lt;/pre&gt;

&lt;p&gt;There are methods to explicitly convert a variable's type as well, such as &lt;span class="inline_code"&gt;parseInt&lt;/span&gt; and &lt;span class="inline_code"&gt;parseFloat&lt;/span&gt; (both of which convert a String to a Number).&lt;/p&gt;

&lt;p&gt;Double negation (!!) can also be used to cast a Number or String to a Boolean.  Consider the following example:&lt;/p&gt;
  
&lt;pre name="code" class="js"&gt;
true == !&amp;quot;0&amp;quot;; // = false
true == !!&amp;quot;0&amp;quot;; // = true
&lt;/pre&gt;

&lt;h5&gt;Conclusion&lt;/h5&gt;
&lt;p&gt;This obviously is not a definitive reference to loose typing in JavaScript (or type coercion for that matter).  I do hope, however, that this will be a useful resource to those who are not familiar with these topics, and a good refresher for those who already are.  I have tried to insure that the above is accurate, but if you notice anything incorrect, please let me know!  And as always, thanks for reading!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1078898499337496912-5252410867450151227?l=blog.jeremymartin.name' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jeremymartin.name/feeds/5252410867450151227/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1078898499337496912&amp;postID=5252410867450151227' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/5252410867450151227'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/5252410867450151227'/><link rel='alternate' type='text/html' href='http://blog.jeremymartin.name/2008/03/understanding-loose-typing-in.html' title='Understanding Loose Typing in JavaScript'/><author><name>Jeremy Martin</name><uri>http://www.blogger.com/profile/03514319709844297772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1078898499337496912.post-6031697947510712256</id><published>2008-03-12T12:23:00.000-07:00</published><updated>2008-03-12T13:33:03.442-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Blogger'/><category scheme='http://www.blogger.com/atom/ns#' term='Misc'/><title type='text'>I've Moved</title><content type='html'>&lt;div style="text-align:center;margin:0 auto 5px 0;"&gt;
  &lt;img class="no-border" src="http://image.bayimg.com/gajmnaabc.jpg" alt="Send to: blog.jeremymartin.name - handle with care" /&gt;
&lt;/div&gt;

&lt;p&gt;Well, under the recommendation of a few &lt;a href="http://www.ethospathoslogosblogos.com/" title="this one's my brother"&gt;fellow&lt;/a&gt; &lt;a href="http://davidwalsh.name/" title="PHP, MySQL, CSS, MooTools, and Everything Else"&gt;bloggers&lt;/a&gt;, I have decided it's time to get my own domain.  From now on my blog will be found at &lt;a href="http://blog.jeremymartin.name"&gt;blog.jeremymartin.name&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For the time being, Blogger will still be serving my posts from the "blog" sub domain, which will allow me to serve any static content from my root level domain.  For me, this beats all the static-page-in-Blogger hacks out there, and I will have a greater degree of control over the site.  Thanks to everyone who reads!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1078898499337496912-6031697947510712256?l=blog.jeremymartin.name' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jeremymartin.name/feeds/6031697947510712256/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1078898499337496912&amp;postID=6031697947510712256' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/6031697947510712256'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/6031697947510712256'/><link rel='alternate' type='text/html' href='http://blog.jeremymartin.name/2008/03/new-domain.html' title='I&apos;ve Moved'/><author><name>Jeremy Martin</name><uri>http://www.blogger.com/profile/03514319709844297772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1078898499337496912.post-3908107880263601777</id><published>2008-03-11T08:43:00.000-07:00</published><updated>2008-03-11T11:03:32.214-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>My Java 7 Wishlist</title><content type='html'>&lt;p&gt;Well, the &lt;a href="https://jdk7.dev.java.net/" target="new"&gt;JDK7 Project&lt;/a&gt; is underway, and despite the fact that I am being moved into the .NET world for some new projects, I wanted to leave some parting thoughts with the Java community.  By no means do I consider myself the ultimate authority on the following topics, however, these are a few things that I propose would make Java a better, more friendly, more flexible language.&lt;/p&gt;

&lt;p&gt;So here they are, in no particular order, my wish list for Java 7:&lt;/p&gt;

&lt;h5&gt;1. No More Primitives!&lt;/h5&gt;
&lt;p&gt;Seriously, primitives had their place and their time, but it's time to let them go. If you're using a boolean instead of Bool to save system resources, then you need to get a server that was made in the last decade. Performance is no longer a valid argument on this one (and that was about the only argument there ever was). OOP is OOP and primitives &lt;i&gt;don't belong in OOP!&lt;/i&gt;&lt;/p&gt;

&lt;h5&gt;2. Tuples&lt;/h5&gt;
&lt;p&gt;Let me put it this way... how many times have you wanted to do something like this:&lt;/p&gt;

&lt;p&gt;&lt;span class="inline_code"&gt;return (object1, object2);&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;See, now you want tuples too. Of course you always have the option of shoving them into some sort of a generic Collection, and then recasting them on the other side.  But here's the problem: Collection's are meant to hold a collection of objects, they are NOT intended to be a form of community transit.&lt;/p&gt;

&lt;p&gt;Another cool thing about tuples is they let you swap values without using a temporary variable, e.g. &lt;span class="include_code"&gt;(x,y) = (y,x)&lt;/span&gt;.  That one's just for free...&lt;/p&gt;

&lt;h5&gt;3. Singleton Class Modifier&lt;/h5&gt;
&lt;p&gt;Do we need it? No. Would it be nice? Absolutely. Just let rules of a singleton Class be handled by the JVM, rather than leaving "singletoness" to be implemented by the designer.  I suppose more importantly, singletons would be made thread safe by the JVM, a consideration that is often overlooked by singleton design patterns.&lt;/p&gt;

&lt;h5&gt;4. Scriptlets Inside JSP 2.0 Custom Tag Bodies&lt;/h5&gt;
&lt;p&gt;Ya, I know this is JSP, not strictly Java - but I'm stroking with a very broad brush here.  I mean, why in the name of all that is good can't we do this?? Yes, scriptlets are inherently evil since the advent of JSTL, but what about those of us cursed with terabytes of legacy code that we do NOT want to convert to JSTL functions?  Presumably custom tags still implement doBody() at some point or another, which already supports scriptlets.  So again, why???&lt;/p&gt;

&lt;h5&gt;5. Heredoc String Support&lt;/h5&gt;
&lt;p&gt;This again is something that we don't need, but that I would definitely like to see. Java developers generally externalize any Strings large enough to justify heredoc format into a properties file - but this has its limitations; take for example a String that needs to contain a variable.  I really don't care how it's implemented (e.g., StringBuilder, StringBuffer, plain Jane concatenation), but I want it.&lt;/p&gt;

&lt;h5&gt;6. Closures&lt;/h5&gt;
&lt;p&gt;While Java let's you get close to closures (using anonymous inner functions), your code ends up being really ugly and hardly readable.  I think closures would be a big step towards making Java a more flexible language (without hurting your eyes at the same time).&lt;/p&gt;

&lt;h5&gt;7. Rationalize the Collections API&lt;/h5&gt;
&lt;p&gt;This would be big, it would be rough, and it would make a lot of developers angry.  The idea of it actually scares me a little, but I'd contend that it has to happen sooner or later - and the sooner the better.  Since my whole argument here is completely stolen, I'll just let you read it at &lt;a href="http://www.onjava.com/pub/a/onjava/2002/07/31/java3.html?page=2" target="new"&gt;the source&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And that's it.  I wanted to make it a top 10 list, but I really didn't have enough to go on.  I realize several of these topics are controversial - so let's hear it in the comments.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1078898499337496912-3908107880263601777?l=blog.jeremymartin.name' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jeremymartin.name/feeds/3908107880263601777/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1078898499337496912&amp;postID=3908107880263601777' title='16 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/3908107880263601777'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/3908107880263601777'/><link rel='alternate' type='text/html' href='http://blog.jeremymartin.name/2008/03/my-java-7-wishlist.html' title='My Java 7 Wishlist'/><author><name>Jeremy Martin</name><uri>http://www.blogger.com/profile/03514319709844297772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>16</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1078898499337496912.post-5884017564107109470</id><published>2008-03-07T17:45:00.002-08:00</published><updated>2008-03-07T17:50:23.594-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Misc'/><title type='text'>Total Recall</title><content type='html'>&lt;h5&gt;Reason #84 to make sure you're current with your vehicle's recalls:&lt;/h5&gt;

&lt;embed flashVars="altServerURL=http%3A%2F%2Fwww.metacafe.com&amp;playerVars=showStats=no|autoPlay=no|videoTitle="  src="http://www.metacafe.com/fplayer/1144474/total_recall.swf" width="460" height="395" wmode="transparent" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash"&gt; &lt;/embed&gt;&lt;br&gt;&lt;font size = 1&gt;&lt;a href="http://snow.metacafe.com/watch/1144474/total_recall/"&gt;Total Recall&lt;/a&gt;&lt;/font&gt;

&lt;p&gt;Just uncovered this clip on my old computer.  This was a tragic/shocking scene that my wife and I passed down in the L.A. area.  This reminds me that I heard something about a recall concerning the speed control on our Explorer... better get on that...&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1078898499337496912-5884017564107109470?l=blog.jeremymartin.name' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jeremymartin.name/feeds/5884017564107109470/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1078898499337496912&amp;postID=5884017564107109470' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/5884017564107109470'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/5884017564107109470'/><link rel='alternate' type='text/html' href='http://blog.jeremymartin.name/2008/03/total-recall.html' title='Total Recall'/><author><name>Jeremy Martin</name><uri>http://www.blogger.com/profile/03514319709844297772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1078898499337496912.post-1536938175853697257</id><published>2008-03-07T13:37:00.000-08:00</published><updated>2008-03-07T14:08:02.791-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='jQuery'/><category scheme='http://www.blogger.com/atom/ns#' term='Algorithms'/><title type='text'>Efficient Tag Cloud Algorithm</title><content type='html'>&lt;p&gt;Hey all - since tag clouds are so popular these days, I thought I'd make a quick post about the algorithm I'm using to generate my tag cloud.  I found a few sample algorithms already out there, but many of them seemed either inefficient, or didn't return the size that I was expecting.&lt;/p&gt;

&lt;p&gt;Considering that the algorithm I'm using for my blog is running on the client side, I wanted to make sure that it was especially efficient.  Here's what I ended up coming up with.&lt;/p&gt;

&lt;p&gt;First, let's define the variables that are being used:&lt;/p&gt;

&lt;dl class="plugin_options"&gt;
 &lt;dt&gt;maxPercent&lt;/dt&gt;
 &lt;dd&gt;The font size is set as a percentage.  This is the font-size percentage that the largest (most frequent) tag should be set to.&lt;/dd&gt;
 
 &lt;dt&gt;minPercent&lt;/dt&gt;
 &lt;dd&gt;This is the font-size percentage that the smallest (least frequent) tag should be set to.&lt;/dd&gt;
 
 &lt;dt&gt;max&lt;/dt&gt;
 &lt;dd&gt;This is the number of occurences for the most frequent tag.&lt;/dd&gt;
 
 &lt;dt&gt;min&lt;/dt&gt;
 &lt;dd&gt;This is the number of occurences for the least frequent tag.&lt;/dd&gt;
 
 &lt;dt&gt;count&lt;/dt&gt;
 &lt;dd&gt;This variable should be set inside of the link iterator.  It refers to the number of occurences for the current tag.&lt;/dd&gt;
&lt;/dl&gt;

&lt;p&gt;Before I show some sample code for this, let's look at the actual algorithm for calculating the size:&lt;/p&gt;

&lt;pre name="code" class="js"&gt;
var size = minPercent + ((max-(max-(count-min)))*(maxPercent-minPercent)/(max-min));
&lt;/pre&gt;

&lt;p&gt;Since &lt;span class="inline_code"&gt;count&lt;/span&gt; is the only variable that changes during each iteration, we can extract the expression &lt;span class="inline_code"&gt;(maxPercent-minPercent)/(max-min)&lt;/span&gt; into its own constant and define it outside of the loop.  This will save us two subtractions and a division operation for every loop.  This now yields the following algorithm: &lt;/p&gt;

&lt;pre name="code" class="js"&gt;
var multiplier = (maxPercent-minPercent)/(max-min);
var size = minPercent + ((max-(max-(count-min)))*multiplier);
&lt;/pre&gt;

&lt;p&gt;The mathematical brilliance (sorry) behind this simple function isn't immediately obvious by looking at it, but the size returned will adhere to the following rules:
 &lt;ol&gt;
  &lt;li&gt;The least occuring tag(s) will have a font-size of &lt;span class="inline_code"&gt;minPercent&lt;/span&gt;.&lt;/li&gt;
  &lt;li&gt;The most occuring tag(s) will have a font-size of &lt;span class="inline_code"&gt;maxPercent&lt;/span&gt;.&lt;/li&gt;
  &lt;li&gt;Tags with occurence counts in the middle will be scaled linearly.&lt;/li&gt;
 &lt;/ol&gt;
&lt;/p&gt;

&lt;p&gt;Ok, let's look at this algorithm in action.  The sample below uses a few jQuery methods (you all saw it coming), but this algorithm can certainly survive apart from any JS library.  Notice that in the code below, I don't know &lt;span class="inline_code"&gt;min&lt;/span&gt; or &lt;span class="inline_code"&gt;max&lt;/span&gt; at the start.  This means I have to loop through all of the tags twice, calculating these statistics the first time.&lt;/p&gt;

&lt;p&gt;To give this code a real life context, I am generating a tag cloud out of the categories list that blogger generates.  The markup that I am looping through is in the following format:&lt;/p&gt;

&lt;pre name="code" class="xml"&gt;
&amp;lt;div class=&amp;quot;widget-content&amp;quot; id=&amp;quot;categories&amp;quot;&amp;gt;
 &amp;lt;ul&amp;gt;
  &amp;lt;li&amp;gt;
   &amp;lt;a dir=&amp;quot;ltr&amp;quot; href=&amp;quot;http://jmar777.blogspot.com/search/label/jQuery&amp;quot;&amp;gt;jQuery&amp;lt;/a&amp;gt;
   (&amp;lt;span dir=&amp;quot;ltr&amp;quot;&amp;gt;6&amp;lt;/span&amp;gt;)
  &amp;lt;/li&amp;gt;
  &amp;lt;li&amp;gt;
   &amp;lt;a dir=&amp;quot;ltr&amp;quot; href=&amp;quot;http://jmar777.blogspot.com/search/label/jTruncate&amp;quot;&amp;gt;jTruncate&amp;lt;/a&amp;gt;
   (&amp;lt;span dir=&amp;quot;ltr&amp;quot;&amp;gt;2&amp;lt;/span&amp;gt;)
  &amp;lt;/li&amp;gt;
  [etc...]
 &amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/pre&gt;

&lt;p&gt;And here's the heavily commented javascript:&lt;/p&gt;

&lt;pre name="code" class="js"&gt;
$().ready(function() {
 var catContainer = $(&amp;#39;div#categories&amp;#39;);
 // get an array of all the &amp;lt;li&amp;gt;&amp;#39;s
 var categories = catContainer.find(&amp;#39;ul li&amp;#39;);
 var cloudMarkup = &amp;#39;&amp;#39;;
 // set maxPercent/minPercent preferences
 var maxPercent = 150, minPercent = 100;
 // note that max is initialized to a number that I know is lower than the max count
 // and that min is set to a number larger than the known min count
 var max = 1, min = 999, count = 0;
 // loop through each li and calculate statistics
 categories.each(function(i) {
  count = parseInt($(this).find(&amp;#39;span&amp;#39;).text());
  max = (count &amp;gt; max ? count : max);
  min = (min &amp;gt; count ? count : min);
 });
 var total, link, size;
 var multiplier = (maxPercent-minPercent)/(max-min);
 // loop through each li and generate the markup for the new tag cloud
 categories.each(function(i) {
  count = parseInt($(this).find(&amp;#39;span&amp;#39;).text());
  link = $(this).find(&amp;#39;a&amp;#39;);
  size = minPercent + ((max-(max-(count-min)))*multiplier) + &amp;#39;%&amp;#39;;
  cloudMarkup += &amp;#39;&amp;lt;a class=&amp;quot;cloud_link&amp;quot; style=&amp;quot;font-size:&amp;#39; + size + &amp;#39;&amp;quot; href=&amp;quot;&amp;#39; + link.attr(&amp;#39;href&amp;#39;) + &amp;#39;&amp;quot;&amp;gt;&amp;#39; + link.text() + &amp;#39;&amp;lt;/a&amp;gt; &amp;#39;;
 });
 // replace the html content of the parent container with the new tag cloud
 catContainer.html(cloudMarkup);
});
&lt;/pre&gt;

&lt;p&gt;For you jQuery users out there - I am considering turning this into a plugin.  I would like to hear from you what the expected markup should look like.  For example, &lt;span class="inline_code"&gt;&amp;lt;a href=&amp;quot;#&amp;quot; rel=&amp;quot;[count]&amp;quot;&amp;gt;tag&amp;lt;/a&amp;gt;&lt;/span&gt; or &lt;span class="inline_code"&gt;&amp;lt;a href=&amp;quot;#&amp;quot;&amp;gt;tag ([count])&amp;lt;/a&amp;gt;&lt;/span&gt;.  Hopefully we can come up with something that doesn't completely violate the purpose of the rel tag, like that example!  Thanks for your input!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1078898499337496912-1536938175853697257?l=blog.jeremymartin.name' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jeremymartin.name/feeds/1536938175853697257/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1078898499337496912&amp;postID=1536938175853697257' title='19 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/1536938175853697257'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/1536938175853697257'/><link rel='alternate' type='text/html' href='http://blog.jeremymartin.name/2008/03/efficient-tag-cloud-algorithm.html' title='Efficient Tag Cloud Algorithm'/><author><name>Jeremy Martin</name><uri>http://www.blogger.com/profile/03514319709844297772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>19</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1078898499337496912.post-4720634847489887738</id><published>2008-03-03T07:11:00.000-08:00</published><updated>2008-03-03T08:20:28.395-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='jQuery'/><title type='text'>jQuery - It's Here to Stay</title><content type='html'>&lt;p&gt;So anyone who has been following this blog during its infancy knows that I have dedicated a lot of time to &lt;a href="http://jmar777.blogspot.com/search/label/jQuery"&gt;jQuery&lt;/a&gt;.  Although my official title at work is Software Engineer, I have always had sway towards the client side technologies.  Perhaps it's the instant gratification; no compile/build/deploy time, and everyone can appreciate it with no understanding of all the back end magic.&lt;/p&gt;

&lt;p&gt;To cut out the story telling, I've found myself doing a lot more JavaScript-ing over the last few releases than my job description would have suggested.  Never one to re-invent the wheel, I started researching some of the popular JS libraries out there.  This post isn't intended as an analysis of why I eventually settled with jQuery, but suffice it to say that it became the obvious answer to many of our client-side needs.&lt;/p&gt;

&lt;p&gt;After discovering the revolutionary ease of DOM selection, traversal, and manipulation in jQuery, I was then blown away by the level of productivity and logicality that chaining permits.  If I want a &lt;span class="inline_code"&gt;div&lt;/span&gt; to fade in, flash 3 times, and then load some external content, I can group these related actions into one logical chain of events... all on the same line.&lt;/p&gt;

&lt;p&gt;So apparently I became a believer.  But I started wondering lately how popular jQuery has really become?  Most of my immediate peers still drool and grovel over Prototype and Mootools (no offense to these other great libraries).  My initial understanding was that jQuery must be the underdog struggeling to make a name.  Well I did a little research and I was actually surprised by what I found.  Check out these results from a &lt;a href="http://www.google.com/trends?q=jquery%2C+scriptaculous%2C+mootools&amp;ctab=0&amp;geo=all&amp;date=ytd&amp;sort=0" target="new" title="Google Trends: jQuery vs. Scriptaculous vs. Mootools"&gt;Google Trends&lt;/a&gt; comparison:&lt;/p&gt;

&lt;p&gt;&lt;img alt="Google Trends: jQuery vs. Scriptaculous vs. Mootools" src="http://image.bayimg.com/kajocaabb.jpg" /&gt;&lt;/p&gt;

&lt;p&gt;These results are showing the number of Google queries for 'jquery' vs. 'scriptaculous' vs. 'mootools'.  Although the chart doesn't reveal the total number of queries, it would appear that jQuery has received roughly three times the interest of scriptaculous or mootools.  Obviously 'prototype' would have been a fairer comparison, but being a common dictionary term, the results would not truly indicate searches for the JS library.&lt;/p&gt;

&lt;p&gt;This next chart by &lt;a title="Alexa: jquery.com vs. prototype.org vs. mootools.net" href="http://www.alexa.com/data/details/traffic_details/jquery.com?site0=jquery.com&amp;site1=prototypejs.org%2F&amp;site2=mootools.net%2F&amp;y=r&amp;z=3&amp;h=300&amp;w=610&amp;range=6m&amp;size=Medium" target="new"&gt;Alexa&lt;/a&gt; shows the number of page views (as gathered by Alexa) for jquery.com, prototype.js.org, and mootools.net.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Alexa: jquery.com vs. prototype.org vs. mootools.net" src="http://image.bayimg.com/kajobaabb.jpg" /&gt;&lt;/p&gt;

&lt;p&gt;This comparison would indicate that mootools is doing better than the Google Trends chart indicated, however jQuery still has a commanding lead.  This is great news for jQuery developers.  If these numbers are any indication of adoption rates, then we can be sure that development will continue, and be confident in the already supportive community.  Well... what more can I say?  Congrats to John Resig and the whole jQuery team for delivering a great product, and of course to the whole jQuery community for making it a success!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1078898499337496912-4720634847489887738?l=blog.jeremymartin.name' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jeremymartin.name/feeds/4720634847489887738/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1078898499337496912&amp;postID=4720634847489887738' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/4720634847489887738'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/4720634847489887738'/><link rel='alternate' type='text/html' href='http://blog.jeremymartin.name/2008/03/jquery-its-here-to-stay.html' title='jQuery - It&apos;s Here to Stay'/><author><name>Jeremy Martin</name><uri>http://www.blogger.com/profile/03514319709844297772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1078898499337496912.post-6807300132411998475</id><published>2008-02-27T13:38:00.000-08:00</published><updated>2008-04-14T14:35:40.116-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Blogger'/><category scheme='http://www.blogger.com/atom/ns#' term='jQuery'/><title type='text'>Blogger Trick: Style Author Comments Differently with jQuery</title><content type='html'>&lt;p&gt;No doubt you've encountered a blog at one time and noticed the custom styling applied to comments left by the author.  It certainly adds a nice touch - and I wanted to be able to do the same here on Blogger.  My first step towards finding a solution was to examine the comment markup generated by blogger.  Unfortunately, however, it seems that Blogger doesn't indicate author comments in any way that can be accessed through a CSS rule.  Well, I'm not that easily deterred, and eventually I came up with the following approach.&lt;/p&gt;

&lt;p&gt;Before I explain how to implement this solution, let me briefly explain how it works.  If you have ever looked inside your template's html, you have likely noticed some custom tags being used.  In our case, we're concerned with the &lt;span class="inline_code"&gt;data&lt;/span&gt; tag.  If this already sounds unfamiliar to you, I would advice you look at &lt;a href="http://help.blogger.com/bin/answer.py?answer=47270&amp;topic=12488" target="new"&gt;this page&lt;/a&gt; on using the data tag.&lt;/p&gt;

&lt;p&gt;The particular piece of data that we want to access is the &lt;span class="inline_code"&gt;data.userUrl&lt;/span&gt; member.  This member is only made available within the Profile widget, which unfortunately means that if you have disabled the profile on your blog, you're out of luck.  This member is also not available if you have a team blog (sorry).  For the rest of you bloggers (which is still the vast majority of you) this solution will work just great.&lt;/p&gt;

&lt;p&gt;So now, with the preliminaries out of the way, we're going to tell the script to loop through all of the comments on the page.  If the member link on the current comment matches the member link in the profile, then it must be an author comment.  The script will then apply an additional class to the comment, allowing you to style it separately.  All clear?&lt;/p&gt;

&lt;h5&gt;Step 1: Import the jQuery Library&lt;/h5&gt;

&lt;p&gt;In order for this script to work, you will have to import the jQuery library.  Since jQuery let's you directly link to the source, this step is quite trivial.  From your blog's dashboard, you will want to go to the layout tab, and then click "Edit HTML".  Search for the &lt;span class="inline_code"&gt;&amp;lt;head&amp;gt;&lt;/span&gt; tag, and insert the following line directly below it:&lt;/p&gt;

&lt;pre name="code" class="xhtml"&gt;
&amp;lt;script src=&amp;#39;http://code.jquery.com/jquery-latest.min.js&amp;#39; type=&amp;#39;text/javascript&amp;#39;/&amp;gt;
&lt;/pre&gt;

&lt;p&gt;Click "Save Template".  Leave this page open because we'll be needing it in the following steps.&lt;/p&gt;

&lt;h5&gt;Step 2: Insert the Script&lt;/h5&gt;

&lt;p&gt;Now click the check box that says "Expand Widget Templates".  Since the &lt;span class="inline_code"&gt;data.userUrl&lt;/span&gt; member is only available within the Profile widget, that is where we need to insert the script.&lt;/p&gt;

&lt;p style="font-weight:bold;"&gt;If are the only author of your blog, do this:&lt;/p&gt;

&lt;p&gt;Search for the following tag:&lt;/p&gt;

&lt;p&gt;&lt;span class="inline_code"&gt;&amp;lt;b:widget id=&amp;#39;Profile1&amp;#39; locked=&amp;#39;false&amp;#39; title=&amp;#39;xxx&amp;#39; type=&amp;#39;Profile&amp;#39;&amp;gt;&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;Inside of this tag you will find the following line:&lt;/p&gt;

&lt;p&gt;&lt;span class="inline_code"&gt;&amp;lt;b:else/&amp;gt; &amp;lt;!-- normal blog profile --&amp;gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Directly below this line, insert the following script:&lt;/p&gt;

&lt;pre name="code" class="js"&gt;
&amp;lt;script type=&amp;#39;text/javascript&amp;#39;&amp;gt;
$().ready(function() {
 $(&amp;#39;dl#comments-block dt a&amp;#39;).each(function(i) {
  if($(this).attr(&amp;#39;href&amp;#39;) == &amp;#39;&amp;lt;data:userUrl/&amp;gt;&amp;#39;) {
   $(this).parent(&amp;#39;dt&amp;#39;).addClass(&amp;#39;author-comment&amp;#39;).next(&amp;#39;dd.comment-body&amp;#39;).addClass(&amp;#39;author-comment&amp;#39;).next(&amp;#39;dd.comment-footer&amp;#39;).addClass(&amp;#39;author-comment&amp;#39;);
  }
 });
});
&amp;lt;/script&amp;gt;
&lt;/pre&gt;

&lt;p style="font-weight:bold;"&gt;If you have co-authors on your blog, do this:&lt;/p&gt;

&lt;p&gt;Search for the following tag:&lt;/p&gt;

&lt;p&gt;&lt;span class="inline_code"&gt;&amp;lt;b:widget id=&amp;#39;Profile1&amp;#39; locked=&amp;#39;false&amp;#39; title=&amp;#39;xxx&amp;#39; type=&amp;#39;Profile&amp;#39;&amp;gt;&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;Inside this tag, you will find the following tag:&lt;/p&gt;

&lt;p&gt;&lt;span class="inline_code"&gt;&amp;#60;b:if cond=&amp;#39;data:team == &amp;#34;true&amp;#34;&amp;#39;&amp;#62;&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;Immediately beneath this tag, insert the following code:&lt;/p&gt;

&lt;pre name="code" class="js"&gt;
&amp;#60;script type=&amp;#34;text/javascript&amp;#34;&amp;#62;
 var author_urls = new Array();
&amp;#60;/script&amp;#62;
&lt;/pre&gt;

&lt;p&gt;Next, find the following line: &lt;span class="inline_code"&gt;&amp;#60;b:loop values=&amp;#39;data:authors&amp;#39; var=&amp;#39;i&amp;#39;&amp;#62;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Immediately below this line, insert the following code:&lt;/p&gt;

&lt;pre name="code" class="js"&gt;
&amp;#60;script type=&amp;#34;text/javascript&amp;#34;&amp;#62;
 author_urls[author_urls.length] = &amp;#39;&amp;#60;data:i.userUrl/&amp;#62;&amp;#39;;
&amp;#60;/script&amp;#62;
&lt;/pre&gt;

&lt;p&gt;Next, insert the following code right below the closing &lt;span class="inline_code"&gt;ul&lt;/span&gt; tag.

&lt;pre name="code" class="js"&gt;
&amp;#60;script type=&amp;#39;text/javascript&amp;#39;&amp;#62;
$().ready(function() {
 var urlsReg = new RegExp(author_urls.join(&amp;#34;|&amp;#34;));
 $(&amp;#39;dl#comments-block dt a&amp;#39;).each(function(i) {
  if(urlsReg.test($(this).attr(&amp;#39;href&amp;#39;))) {
   $(this).parent(&amp;#39;dt&amp;#39;).addClass(&amp;#39;author-comment&amp;#39;).next(&amp;#39;dd.comment-body&amp;#39;).addClass(&amp;#39;author-comment&amp;#39;).next(&amp;#39;dd.comment-footer&amp;#39;).addClass(&amp;#39;author-comment&amp;#39;);
  }
 });
});
&amp;#60;/script&amp;#62;
&lt;/pre&gt;

&lt;p&gt;That takes care of all the JavaScript parts.  Now all that's left to do is to style it.&lt;/p&gt;

&lt;h5&gt;Step 3: Update your CSS&lt;/h5&gt;

&lt;p&gt;If you look at the markup that Blogger generates, you will notice that each comment is made up of a &lt;span class="inline_code"&gt;dt&lt;/span&gt; tag followed by two &lt;span class="inline_code"&gt;dd&lt;/span&gt; tags.  At the time of writing this, I am using the following additional CSS:&lt;/p&gt;

&lt;pre name="code" class="css"&gt;
dl#comments-block dt.author-comment {
  background-image: none;
  background-color: #EDE5BE;
  margin-bottom: 0px;
  padding: 6px 0 6px 10px;
  border: 1px solid #ccc;
  border-bottom: 1px solid #FFF7CF;
}

dl#comments-block dd.comment-body.author-comment {
  color: #593622;
  background-color: #EDE5BE;
  margin-top: 0px;
  margin-bottom: 0px;
  padding: 10px;
  border: 1px solid#ccc;
  border-top: 1px solid #CBC4AC;
}

dl#comments-block dd.comment-footer.author-comment {
  font-size: .8em;
  background-color: #CBC39C;
  padding: 3px;
  margin-top: 0px;
  float: right;
  border: 1px solid #ccc;
  border-top: none;
}
&lt;/pre&gt;

&lt;p&gt;To add these styles, simply paste them right above the &lt;span class="inline_code"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt; tag.&lt;/p&gt;

&lt;h5&gt;You're Done!&lt;/h5&gt;

&lt;p&gt;That's it!  Just hit "Save Template" and view your blog.  To see the script in action, view my comment below this post.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1078898499337496912-6807300132411998475?l=blog.jeremymartin.name' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jeremymartin.name/feeds/6807300132411998475/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1078898499337496912&amp;postID=6807300132411998475' title='57 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/6807300132411998475'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/6807300132411998475'/><link rel='alternate' type='text/html' href='http://blog.jeremymartin.name/2008/02/blogger-trick-style-author-comments.html' title='Blogger Trick: Style Author Comments Differently with jQuery'/><author><name>Jeremy Martin</name><uri>http://www.blogger.com/profile/03514319709844297772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>57</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1078898499337496912.post-2921530144659083623</id><published>2008-02-26T12:15:00.000-08:00</published><updated>2008-03-07T14:10:07.567-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='jTruncate'/><category scheme='http://www.blogger.com/atom/ns#' term='jQuery'/><title type='text'>jTruncate in Action</title><content type='html'>&lt;script src="http://jtruncate.googlecode.com/svn/trunk/jquery.jtruncate.js" type="text/javascript"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;
 $().ready(function() {
  $('#jTruncate_example1').jTruncate();
  
  $('#jTruncate_example2').jTruncate({
   length: 200,
   minTrail: 0,
   moreText: "[see all]",
   lessText: "[hide extra]",
   ellipsisText: " (truncated)",
   moreAni: "fast",
   lessAni: 2000
  });
 });
&lt;/script&gt;

&lt;p&gt;This is the demonstration page for the jTruncate plugin for jQuery.  If you are looking for the jTruncate homepage, 
go &lt;a href="http://jmar777.blogspot.com/2008/02/jtruncate-text-truncation-for-jquery.html"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h5&gt;Plain Jane Example&lt;/h5&gt;

&lt;p&gt;jTruncate is called in the same way that most other jQuery plugins are called.  The example below is using the following code, 
that accepts all the default options.&lt;/p&gt;

&lt;pre name="code" class="js"&gt;
$().ready(function() {
 $(&amp;#39;#example1&amp;#39;).jTruncate();
});

&lt;/pre&gt;

&lt;div style="margin: 15px 0pt; text-align: center;"&gt;
 &lt;div id="jTruncate_example1" style="border: 1px solid rgb(204, 204, 204); padding: 10px; margin-left: auto; margin-right: auto; width: 320px; background-color: rgb(239, 239, 209); text-align: left;"&gt;
  Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Etiam fringilla, purus a ultrices blandit,
  odio ante scelerisque neque, vitae imperdiet odio velit ac nisl. Sed tortor metus, placerat condimentum,
  feugiat in, feugiat adipiscing, mi. Donec pulvinar sem vitae leo. Vestibulum eget lectus et ligula hendrerit
  pharetra. Sed porta justo ac nisl. Aliquam nisi erat, pellentesque sed, sagittis eu, fringilla sit amet,
  dolor. Nam ac mi. Pellentesque pede purus, mattis aliquet, semper nec, cursus a, orci. Duis bibendum nibh
  ac massa. Integer eu tortor. Aenean convallis quam at nunc. Nunc mollis tincidunt nisi. Suspendisse mauris
  odio, iaculis ut, feugiat vitae, ultrices in, tortor. Quisque at elit. In hac habitasse platea dictumst.
 &lt;/div&gt;
&lt;/div&gt;

&lt;h5&gt;jTruncate Options&lt;/h5&gt;

&lt;p&gt;jTruncate allows you to customize nearly every aspect of the truncation operation.  The following options are provided:&lt;/p&gt;

&lt;dl class="plugin_options"&gt;
 &lt;dt&gt;length: &lt;i&gt;Defaults to 300&lt;/i&gt;&lt;/dt&gt;
 &lt;dd&gt;The number of characters to display before truncating.&lt;/dd&gt;
 
 &lt;dt&gt;minTrail: &lt;i&gt;Defaults to 20&lt;/i&gt;&lt;/dt&gt;
 &lt;dd&gt;The minimum number of "extra" characters required to truncate.  This option allows you to prevent truncation of a section of text that is only 
  a few characters longer than the specified length.&lt;/dd&gt;
  
 &lt;dt&gt;moreText: &lt;i&gt;Defaults to "more"&lt;/i&gt;&lt;/dt&gt;
 &lt;dd&gt;The text to use for the "more" link.&lt;/dd&gt;
 
 &lt;dt&gt;lessText: &lt;i&gt;Defaults to "less"&lt;/i&gt;&lt;/dt&gt;
 &lt;dd&gt;The text to use for the "less" link.&lt;/dd&gt;
  
 &lt;dt&gt;ellipsisText: &lt;i&gt;Defaults to "..."&lt;/i&gt;&lt;/dt&gt;
 &lt;dd&gt;The text to append to the truncated portion.&lt;/dd&gt;
  
 &lt;dt&gt;moreAni: &lt;i&gt;Defaults to an empty string&lt;/i&gt;&lt;/dt&gt;
 &lt;dd&gt;The speed argument for the show() method (as specified &lt;a href="http://docs.jquery.com/Effects/show" target="new"&gt;here&lt;/a&gt;).&lt;dd&gt;
 
 &lt;dt&gt;lessAni: &lt;i&gt;Defaults to an empty string&lt;/i&gt;&lt;/dt&gt;
 &lt;dd&gt;The speed argument for the hide() method (as specified &lt;a href="http://docs.jquery.com/Effects/hide" target="new"&gt;here&lt;/a&gt;).&lt;/dd&gt;
&lt;/dl&gt;

&lt;h5&gt;Custom jTruncate Example&lt;/h5&gt;

&lt;p&gt;The following example demonstrates how to override the defaults described above.&lt;/p&gt;

&lt;pre name="code" class="js"&gt;
$().ready(function() {
 $(&amp;#39;#example2&amp;#39;).jTruncate({
  length: 200,
  minTrail: 0,
  moreText: &amp;quot;[see all]&amp;quot;,
  lessText: &amp;quot;[hide extra]&amp;quot;,
  ellipsisText: &amp;quot; (truncated)&amp;quot;,
  moreAni: &amp;quot;fast&amp;quot;,
  lessAni: 2000
 });
});

&lt;/pre&gt;

&lt;div style="margin: 15px 0pt; text-align: center;"&gt;
 &lt;div id="jTruncate_example2" style="border: 1px solid rgb(204, 204, 204); padding: 10px; margin-left: auto; margin-right: auto; width: 320px; background-color: rgb(239, 239, 209); text-align: left;"&gt;
  Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Etiam fringilla, purus a ultrices blandit,
  odio ante scelerisque neque, vitae imperdiet odio velit ac nisl. Sed tortor metus, placerat condimentum,
  feugiat in, feugiat adipiscing, mi. Donec pulvinar sem vitae leo. Vestibulum eget lectus et ligula hendrerit
  pharetra. Sed porta justo ac nisl. Aliquam nisi erat, pellentesque sed, sagittis eu, fringilla sit amet,
  dolor. Nam ac mi. Pellentesque pede purus, mattis aliquet, semper nec, cursus a, orci. Duis bibendum nibh
  ac massa. Integer eu tortor. Aenean convallis quam at nunc. Nunc mollis tincidunt nisi. Suspendisse mauris
  odio, iaculis ut, feugiat vitae, ultrices in, tortor. Quisque at elit. In hac habitasse platea dictumst.
 &lt;/div&gt;
&lt;/div&gt;

&lt;h5&gt;Special Considerations&lt;/h5&gt;

&lt;p&gt;Note that if you override the default animation options, you will notice a "new line" inserted at the point of truncation.  This is because the hide/show methods require the animated 
element to be block level, and thus will begin on its own line.&lt;/p&gt;

&lt;p&gt;Also note that jTruncate chooses the split location by starting at the length you specify (or the default) and then finds the next space.  This is to prevent truncation in the middle of
an html tag.  This implies that the text needs to have spaces in it (duh), and that any tags within the truncated text cannot contain a space (i.e. &lt;span class="inline_code"&gt;&amp;lt;p id=&amp;quot;myP&amp;quot;&amp;gt;&lt;/span&gt; = bad).&lt;/p&gt;

&lt;p&gt;Thank you for visiting, and if you have any questions/suggestions at all, just let me know in the comments!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1078898499337496912-2921530144659083623?l=blog.jeremymartin.name' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jeremymartin.name/feeds/2921530144659083623/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1078898499337496912&amp;postID=2921530144659083623' title='59 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/2921530144659083623'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/2921530144659083623'/><link rel='alternate' type='text/html' href='http://blog.jeremymartin.name/2008/02/jtruncate-in-action.html' title='jTruncate in Action'/><author><name>Jeremy Martin</name><uri>http://www.blogger.com/profile/03514319709844297772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>59</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1078898499337496912.post-5284963351749518519</id><published>2008-02-26T11:38:00.000-08:00</published><updated>2008-02-27T12:58:47.081-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='jTruncate'/><category scheme='http://www.blogger.com/atom/ns#' term='jQuery'/><title type='text'>jTruncate - Text Truncation for jQuery</title><content type='html'>&lt;p&gt;Welcome and thanks for visiting!  This is the official home page for the jTruncate plugin for jQuery.  In a nutshell, jTruncate provides simple yet customizable truncation for text entities in your web page.&lt;/p&gt;

&lt;h5&gt;Download&lt;/h5&gt;

&lt;p&gt;The latest version of jTruncate can be found at the following links:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://jtruncate.googlecode.com/svn/trunk/jquery.jtruncate.js" target="new"&gt;Uncompressed source for jTruncate&lt;/a&gt; (1.71KB)&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://jtruncate.googlecode.com/svn/trunk/jquery.jtruncate.pack.js" target="new"&gt;Packed version of jTruncate&lt;/a&gt; (only 952 bytes!)&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;Instructions/Examples&lt;/h5&gt;

&lt;p&gt;For usage instructions and working examples of the jTruncate plugin, look &lt;a href="http://jmar777.blogspot.com/2008/02/jtruncate-in-action.html"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h5&gt;Testers wanted!&lt;/h5&gt;

&lt;p&gt;To date I have tested jTruncate in FF2, IE6+, and Safari 3 (for windows).  If you are running a browser other than what I have listed, please let me know how it performs!  Due to the limited testing thus far, I am currently releasing jTruncate at version 0.8 - but it is a simple script and (until proven otherwise) I consider it to be stable.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1078898499337496912-5284963351749518519?l=blog.jeremymartin.name' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jeremymartin.name/feeds/5284963351749518519/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1078898499337496912&amp;postID=5284963351749518519' title='22 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/5284963351749518519'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/5284963351749518519'/><link rel='alternate' type='text/html' href='http://blog.jeremymartin.name/2008/02/jtruncate-text-truncation-for-jquery.html' title='jTruncate - Text Truncation for jQuery'/><author><name>Jeremy Martin</name><uri>http://www.blogger.com/profile/03514319709844297772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>22</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1078898499337496912.post-4720785125942476981</id><published>2008-02-08T08:53:00.000-08:00</published><updated>2008-06-24T06:44:06.835-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='jQuery'/><title type='text'>Easy Multi Select Transfer with jQuery</title><content type='html'>&lt;p&gt;I'm sure that at some point or another you've encountered a form widget like the one below, allowing options to be traded from one multi select to another.&lt;/p&gt;

&lt;script type="text/javascript"&gt;
$().ready(function() {
 $('#multiTransferExample #add').click(function() {
  return !$('#multiTransferExample #select1 option:selected').remove().appendTo('#multiTransferExample #select2');
 });
 $('#multiTransferExample #remove').click(function() {
  return !$('#multiTransferExample #select2 option:selected').remove().appendTo('#multiTransferExample #select1');
 });
});
&lt;/script&gt;


&lt;style type="text/css"&gt;
 #multiTransferExample a {
  display: block;
  border: 1px solid #aaa;
  text-decoration: none;
  background-color: #fafafa;
  color: #123456;
  margin: 2px;
  clear: both;
 }
 #multiTransferExample div {
  float:left;
  text-align: center;
  margin: 10px;
 }
 #multiTransferExample select {
  width: 100px;
  height: 80px;
 }
&lt;/style&gt;


&lt;div id="multiTransferExample" style="margin-left:30px;"&gt;
&lt;div&gt;
 &lt;select multiple id="select1"&gt;
  &lt;option value="1"&gt;Option 1&lt;/option&gt;
  &lt;option value="2"&gt;Option 2&lt;/option&gt;
  &lt;option value="3"&gt;Option 3&lt;/option&gt;
  &lt;option value="4"&gt;Option 4&lt;/option&gt;
 &lt;/select&gt;
 &lt;a href="#" id="add"&gt;add &amp;gt;&amp;gt;&lt;/a&gt;
&lt;/div&gt;
&lt;div&gt;
 &lt;select multiple id="select2"&gt;&lt;/select&gt;
 &lt;a href="#" id="remove"&gt;&amp;lt;&amp;lt; remove&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div style="clear:both;"&gt;&lt;/div&gt;

&lt;p&gt;I recently encountered a tutorial over at &lt;a href="http://www.quirksmode.org/js/transfer.html" target="new"&gt;Quirks Mode&lt;/a&gt; on creating such a widget. While not a bad script, when all was said and done it was coming up on 40 lines of JS.  I suppose that's not horrible, but we're talking about some simple functionality.&lt;/p&gt;

&lt;p&gt;This struck me as a perfect example to demonstrate the simple and compact nature of jQuery coding.  The widget operating above is running off of the following code: &lt;/p&gt;

&lt;pre name="code" class="js"&gt;
$().ready(function() {
 $(&amp;#39;#add&amp;#39;).click(function() {
  return !$(&amp;#39;#select1 option:selected&amp;#39;).remove().appendTo(&amp;#39;#select2&amp;#39;);
 });
 $(&amp;#39;#remove&amp;#39;).click(function() {
  return !$(&amp;#39;#select2 option:selected&amp;#39;).remove().appendTo(&amp;#39;#select1&amp;#39;);
 });
});
&lt;/pre&gt;

&lt;p&gt;That's it... 8 lines.&lt;/p&gt;

&lt;p&gt;If you'd like to try it out, here's a working test page:&lt;/p&gt;

&lt;pre name="code" class="xml"&gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
 &amp;lt;script src=&amp;quot;js/jquery.js&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
 &amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;
  $().ready(function() {
   $(&amp;#39;#add&amp;#39;).click(function() {
    return !$(&amp;#39;#select1 option:selected&amp;#39;).remove().appendTo(&amp;#39;#select2&amp;#39;);
   });
   $(&amp;#39;#remove&amp;#39;).click(function() {
    return !$(&amp;#39;#select2 option:selected&amp;#39;).remove().appendTo(&amp;#39;#select1&amp;#39;);
   });
  });
 &amp;lt;/script&amp;gt;
 
 &amp;lt;style type=&amp;quot;text/css&amp;quot;&amp;gt;
  a {
   display: block;
   border: 1px solid #aaa;
   text-decoration: none;
   background-color: #fafafa;
   color: #123456;
   margin: 2px;
   clear:both;
  }
  div {
   float:left;
   text-align: center;
   margin: 10px;
  }
  select {
   width: 100px;
   height: 80px;
  }
 &amp;lt;/style&amp;gt;
 
&amp;lt;/head&amp;gt;

&amp;lt;body&amp;gt;
 &amp;lt;div&amp;gt;
  &amp;lt;select multiple id=&amp;quot;select1&amp;quot;&amp;gt;
   &amp;lt;option value=&amp;quot;1&amp;quot;&amp;gt;Option 1&amp;lt;/option&amp;gt;
   &amp;lt;option value=&amp;quot;2&amp;quot;&amp;gt;Option 2&amp;lt;/option&amp;gt;
   &amp;lt;option value=&amp;quot;3&amp;quot;&amp;gt;Option 3&amp;lt;/option&amp;gt;
   &amp;lt;option value=&amp;quot;4&amp;quot;&amp;gt;Option 4&amp;lt;/option&amp;gt;
  &amp;lt;/select&amp;gt;
  &amp;lt;a href=&amp;quot;#&amp;quot; id=&amp;quot;add&amp;quot;&amp;gt;add &amp;amp;gt;&amp;amp;gt;&amp;lt;/a&amp;gt;
 &amp;lt;/div&amp;gt;
 &amp;lt;div&amp;gt;
  &amp;lt;select multiple id=&amp;quot;select2&amp;quot;&amp;gt;&amp;lt;/select&amp;gt;
  &amp;lt;a href=&amp;quot;#&amp;quot; id=&amp;quot;remove&amp;quot;&amp;gt;&amp;amp;lt;&amp;amp;lt; remove&amp;lt;/a&amp;gt;
 &amp;lt;/div&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/pre&gt;

&lt;p&gt;As was mentioned in the comments below, the following (slightly modified) code can be used to automatically select all options in the second select box before submitting (thanks Charlie!).&lt;/p&gt;

&lt;pre name="code" class="js"&gt;
$(&amp;#39;form&amp;#39;).submit(function() {
 $(&amp;#39;#select2 option&amp;#39;).each(function(i) {
  $(this).attr(&amp;quot;selected&amp;quot;, &amp;quot;selected&amp;quot;);
 });
});
&lt;/pre&gt;

&lt;p&gt;Just make sure you include that snippet inside the &lt;span class="inline_code"&gt;$().ready()&lt;/span&gt; method.&lt;/p&gt;

&lt;div class="update"&gt;
  &lt;h5&gt;Update! (2/28/2008)&lt;/h5&gt;
  &lt;p&gt;To prevent the page from scrolling to the top whenever a user clicks a button (in some browsers), I added &lt;span class="inline_code"&gt;return false;&lt;/span&gt; to the click event handlers.&lt;/p&gt;
  &lt;h5&gt;(3/07/2008)&lt;/h5&gt;
  &lt;p&gt;I included Charlie's suggestion from the comments into the main article.  Thanks again Charlie!  I also updated the the click event handlers to return false on the same line.  Now it's only 8 lines!&lt;/p&gt;
  &lt;h5&gt;(6/24/2008)&lt;/h5&gt;
  &lt;p&gt;&lt;a href="http://davidwalsh.name"&gt;David Walsh&lt;/a&gt; has done an excellent port of this script for the Mootools library.  You'll notice that the libraries allow for very similar syntax and nearly identical flow of logic.  &lt;a href="http://davidwalsh.name/multi-select-transfers-using-mootools-12"&gt;
Check it out&lt;/a&gt;!&lt;/p&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1078898499337496912-4720785125942476981?l=blog.jeremymartin.name' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jeremymartin.name/feeds/4720785125942476981/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1078898499337496912&amp;postID=4720785125942476981' title='135 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/4720785125942476981'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/4720785125942476981'/><link rel='alternate' type='text/html' href='http://blog.jeremymartin.name/2008/02/easy-multi-select-transfer-with-jquery.html' title='Easy Multi Select Transfer with jQuery'/><author><name>Jeremy Martin</name><uri>http://www.blogger.com/profile/03514319709844297772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>135</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1078898499337496912.post-857404439471359787</id><published>2008-02-06T07:36:00.000-08:00</published><updated>2008-03-10T06:43:04.766-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Hibernate'/><title type='text'>Java, Reflection, Hibernate Proxy Objects, and Confetti</title><content type='html'>&lt;p&gt;After spending the last 3 days scratching my head and pushing Google to its theoretical limits, I have just experienced the ever-satisfying thrill of success.  It was one of those moments where a little hole appears in the clouds and a beam of light illuminates my desk while gold and silver confetti float down from the overhead sprinklers.  It really was that good; I nearly made an announcement over the intercom.&lt;/p&gt;

&lt;p&gt;So here's the setup: we have a web application running on a Weblogic Portal server and we're using &lt;a href="http://www.hibernate.org" target="new"&gt;Hibernate&lt;/a&gt; and &lt;a href="http://www.springframework.org/" target="new"&gt;Spring&lt;/a&gt;.  Due to application growth and an expanding data model, we decided it was time to turn lazy loading on (with respect to Hibernate).  Meanwhile I'm working on some form processing logic that (for the sake of this discussion) needed to be a runtime annotation consumer.&lt;/p&gt;

&lt;p&gt;The section of code was to determine whether a form had values for all of the "Recommended Fields".  The recommended fields were designated via a RecommendedField annotation in the model class.  All this method knows is that the particular model object will extend MySuperClass.  So it's pretty straight forward.  Here's a basic outline of what I had going:&lt;/p&gt;

&lt;pre name="code" class="java"&gt;
public static boolean isComplete(MySuperClass object) {

 Method[] methods = object.getClass().getMethods();
 for(Method method : methods) {
  RecommendedField rField = method.getAnnotation(RecommendedField.class);
  if( null != rField) {
   // do some logic, then return true or false 
  }
 }
 
 return true;
}
&lt;/pre&gt;

&lt;p&gt;Nothing seems glaringly wrong in the code above, but to my consternation, method.getAnnotation() always returned null.  Around this time I came to understand one of the side effects of Hibernate lazy loading.  In order to allow lazy access to any relational objects, Hibernate returns a "proxy" object that essentially wraps and mimics the object that you wanted.  This way when you call a getter, instead of throwing a NullPointerException, Hibernate can retrieve the result from the database.&lt;/p&gt;

&lt;p&gt;Great... so what now?  While the proxy object will suffice whenever you need to access a public property or method, it quickly becomes apparent that introspection and reflection present a problem.  Since the proxy object is not truly an instance of the class that it is wrapping, metadata (such as annotations) are not there.&lt;/p&gt;

&lt;p&gt;In truth, this realization was the key to solving the problem.  Understanding that the annotations simply didn't exist on the object that I was inspecting prompted me to explore how to retrieve the non-proxy version of the object.  Here is the solution that I ultimately came up with: &lt;/p&gt;

&lt;pre name="code" class="java"&gt;
public static boolean isComplete(MySuperClass object) {
 /*
  *  The type casting below is necessary in order to read the annotations on the object's methods.
  *  The "MySuperClass" object that is passed into this method is really a Hibernate proxy object 
  *  that wraps the MySuperClass object (due to Hibernate's lazy loading).
  */
 if (object instanceof HibernateProxy) {
  object = (MySuperClass)((HibernateProxy)object).getHibernateLazyInitializer().getImplementation();
 }
  
 Method[] methods = object.getClass().getMethods();
 for(Method method : methods) {
  RecommendedField rField = method.getAnnotation(RecommendedField.class);
  if( null != rField) {
   // do some logic, then return true or false 
  }
 }
 
 return true;
}
&lt;/pre&gt;

&lt;p&gt;*Cue confetti*&lt;/p&gt;
&lt;p&gt;You'll notice that the commented addition is rather peculiar.  It essentially takes the proxy object that was passed in and casts it as a HibernateProxy object.  Calling getImplementation() returns a generic object, which I can then recast as a MySuperClass object (which is what it claimed to be in the first place).  Since the object I am working with is now a real and true instance of MySuperClass, I can inspect the methods and their annotations without any problems.&lt;/p&gt;

&lt;p&gt;There is a word of warning to throw in about this solution: since I am replacing the proxy object with the real object, my assumption is that it is now detached from the Hibernate session.  Attempts at lazy loading on the object would most likely return null or throw a LazyLoadException (I have not tested to verify).  In my case I don't need to access any more data, so it's not a problem.  If your circumstances are different, you can simply create a new instantiation out of the casted object, or attempt to reattach the object to the Hibernate session when you're done.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1078898499337496912-857404439471359787?l=blog.jeremymartin.name' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jeremymartin.name/feeds/857404439471359787/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1078898499337496912&amp;postID=857404439471359787' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/857404439471359787'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/857404439471359787'/><link rel='alternate' type='text/html' href='http://blog.jeremymartin.name/2008/02/java-reflection-hibernate-proxy-objects.html' title='Java, Reflection, Hibernate Proxy Objects, and Confetti'/><author><name>Jeremy Martin</name><uri>http://www.blogger.com/profile/03514319709844297772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1078898499337496912.post-3612402992787556312</id><published>2008-02-03T13:53:00.000-08:00</published><updated>2008-02-26T13:57:23.028-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='jQuery'/><title type='text'>Building Your First jQuery Plugin</title><content type='html'>&lt;script type="text/javascript"&gt;
(function($){
 $.fn.truncate_example = function(options) {
    
  var defaults = {
   length: 300,
   minTrail: 20,
   moreText: "more",
   lessText: "less",
   ellipsisText: "..."
  };
  
  var options = $.extend(defaults, options);
    
  return this.each(function() {
   obj = $(this);
   var body = obj.html();
   
   if(body.length &gt; options.length + options.minTrail) {
    var splitLocation = body.indexOf(' ', options.length);
    if(splitLocation != -1) {
     // truncate tip
     var splitLocation = body.indexOf(' ', options.length);
     var str1 = body.substring(0, splitLocation);
     var str2 = body.substring(splitLocation, body.length - 1);
     obj.html(str1 + '&lt;span class="truncate_ellipsis"&gt;' + options.ellipsisText + 
      '&lt;/span&gt;' + '&lt;span class="truncate_more"&gt;' + str2 + '&lt;/span&gt;');
     obj.find('.truncate_more').css("display", "none");
     
     // insert more link
     obj.append(
      '&lt;div class="clearboth"&gt;' +
       '&lt;a href="#" class="truncate_more_link"&gt;' + options.moreText + '&lt;/a&gt;' +
      '&lt;/div&gt;'
     );

     // set onclick event for more/less link
     var moreLink = $('.truncate_more_link', obj);
     var moreContent = $('.truncate_more', obj);
     var ellipsis = $('.truncate_ellipsis', obj);
     moreLink.click(function() {
      if(moreLink.text() == options.moreText) {
       moreContent.show('normal');
       moreLink.text(options.lessText);
       ellipsis.css("display", "none");
      } else {
       moreContent.hide('normal');
       moreLink.text(options.moreText);
       ellipsis.css("display", "inline");
      }
      return false;
       });
    }
   } // end if
   
  });
 };
})(jQuery);


// END PLUGIN CODE

$().ready(function() {
  $('#example1').truncate_example();
  $('#example2').truncate_example( {
    length: 120,
    minTrail: 10,
    moreText: 'show more',
    lessText: 'show less',
    ellipsisText: ' [there&amp;#39;s more...]'
  });
});

&lt;/script&gt;




&lt;p&gt;So you were out on your quest to find &lt;a href="http://en.wikipedia.org/wiki/The_Answer_to_Life,_the_Universe,_and_Everything" target="new"&gt;the answer to life, the universe, and everything&lt;/a&gt;, when &lt;span style="color:#8F5959;font-style:italic;font-weight:bold;"&gt;blam&lt;/span&gt;, you found jQuery. Yes, I know, you were expecting &lt;a href="http://www.google.com/search?source=ig&amp;hl=en&amp;rlz=1G1GGLQ_ENUS253&amp;q=the+answer+to+life%2C+the+universe%2C+and+everything&amp;btnG=Google+Search" target="new"&gt;42&lt;/a&gt;, but too all of our surprise, it was &lt;a href="http://www.jquery.com" target="new"&gt;jQuery&lt;/a&gt;.  So what's next?  Build your own plugin!&lt;/p&gt;

&lt;p&gt;While some are intimidated by the thought of creating their own plugin, the truth is that jQuery is built with an infinitely friendly plugin architecture. If you've gotten comfortable with the basics of jQuery coding, then you're certainly ready to develop your own plugin.  This tutorial will take you step by step through creating your very own truncation plugin. Say, for example, you have a "tip of the day" widget on your home page.  This plugin will let you truncate it to a specified length, with a link to expand it to view it's full content.  Here's a working example: &lt;/p&gt;

&lt;div style="text-align:center;margin:15px 0 15px 0;"&gt;
&lt;div id="example1" style="margin-left:auto;margin-right:auto;width:320px;padding:10px;background-color:#EFEFD1;border:1px solid #ccc;text-align:left;"&gt;
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Etiam fringilla, purus a ultrices blandit,
  odio ante scelerisque neque, vitae imperdiet odio velit ac nisl. Sed tortor metus, placerat condimentum,
  feugiat in, feugiat adipiscing, mi. Donec pulvinar sem vitae leo. Vestibulum eget lectus et ligula hendrerit
  pharetra. Sed porta justo ac nisl. Aliquam nisi erat, pellentesque sed, sagittis eu, fringilla sit amet,
  dolor. Nam ac mi. Pellentesque pede purus, mattis aliquet, semper nec, cursus a, orci. Duis bibendum nibh
  ac massa. Integer eu tortor. Aenean convallis quam at nunc. Nunc mollis tincidunt nisi. Suspendisse mauris
  odio, iaculis ut, feugiat vitae, ultrices in, tortor. Quisque at elit. In hac habitasse platea dictumst.
&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Note that if JavaScript is disabled (or not supported) the content will simply display in it's entirety.&lt;/p&gt;

&lt;p&gt;You ready?  Let's dig in...&lt;/p&gt;

&lt;h5&gt;Step 1&lt;/h5&gt;
&lt;p&gt;The first step is to extend the actual jQuery object with the function that we wish to add.  In our case, we wish to add "truncation" functionality.  So here's where to start: create a &lt;span class="file_path"&gt;jquery.truncate.js&lt;/span&gt; file and save it with the following code:&lt;/p&gt;
&lt;pre name="code" class="js"&gt;
$.fn.truncate = function(options) {

   return this.each(function() {

   });
};

&lt;/pre&gt;
&lt;p&gt;Now you may have heard that plugin developers should not user the &lt;span class="inline_code"&gt;$&lt;/span&gt; alias, as this can result in conflicts with other libraries.  This is only partially true.  The following snippet is the same as the one above, except that we pass &lt;span class="inline_code"&gt;jQuery&lt;/span&gt; into the function, allowing us to use an alias we want.  We'll stick with &lt;span class="inline_code"&gt;$&lt;/span&gt;.&lt;/p&gt;

&lt;pre name="code" class="js"&gt;
(function($){
 $.fn.truncate = function() {

    return this.each(function() {

    });
 };
})(jQuery);
&lt;/pre&gt;

&lt;h5&gt;Step 2&lt;/h5&gt;
&lt;p&gt;Before we go any further, let's create a simple test page that we can use to test our plugin.  Create a page and call it &lt;span class="file_path"&gt;whatever_you_want.html&lt;/span&gt;.  Insert the following code.  As you can see I placed both the jQuery library and the plugin inside a folder named &lt;span class="file_path"&gt;js&lt;/span&gt;.  Note that we are already invoking our plugin in this snippet, although we have not yet coded any behavior.&lt;/p&gt;
&lt;pre name="code" class="xhtml"&gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
 &amp;lt;title&amp;gt;Truncation Plugin Test&amp;lt;/title&amp;gt;
 &amp;lt;script src=&amp;quot;js/jquery.js&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
 &amp;lt;script src=&amp;quot;js/jquery.truncate.js&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
 
 &amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;
  $().ready(function() {
   $(&amp;#39;.tip&amp;#39;).truncate();
  });
 &amp;lt;/script&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
 &amp;lt;div class=&amp;quot;tip&amp;quot; style=&amp;quot;width:200px;background-color:#ccc;padding:10px;&amp;quot;&amp;gt;
  Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Etiam fringilla, purus a ultrices blandit,
  odio ante scelerisque neque, vitae imperdiet odio velit ac nisl. Sed tortor metus, placerat condimentum,
  feugiat in, feugiat adipiscing, mi. Donec pulvinar sem vitae leo. Vestibulum eget lectus et ligula hendrerit
  pharetra. Sed porta justo ac nisl. Aliquam nisi erat, pellentesque sed, sagittis eu, fringilla sit amet,
  dolor. Nam ac mi. Pellentesque pede purus, mattis aliquet, semper nec, cursus a, orci. Duis bibendum nibh
  ac massa. Integer eu tortor. Aenean convallis quam at nunc. Nunc mollis tincidunt nisi. Suspendisse mauris
  odio, iaculis ut, feugiat vitae, ultrices in, tortor. Quisque at elit. In hac habitasse platea dictumst.
 &amp;lt;/div&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/pre&gt;

&lt;h5&gt;Step 3&lt;/h5&gt;
&lt;p&gt;The next thing we want to do is provide a mechanism for the user to customize the plugin.  While we want to make the plugin as flexible as possible, we should also provide defaults so that the user isn't forced into providing a long list of parameters.  We can easily do this using jQuery's &lt;span class="inline_code"&gt;&lt;a href="http://docs.jquery.com/Utilities/jQuery.extend" target="new"&gt;extend&lt;/a&gt;&lt;/span&gt; method.  Update your plugin to match the following:&lt;/p&gt;

&lt;pre name="code" class="js"&gt;
(function($){
 $.fn.truncate = function(options) {

  var defaults = {
   length: 300,
   minTrail: 20,
   moreText: &amp;quot;more&amp;quot;,
   lessText: &amp;quot;less&amp;quot;,
   ellipsisText: &amp;quot;...&amp;quot;
  };
  var options = $.extend(defaults, options);
    
  return this.each(function() {

  });
 };
})(jQuery);
&lt;/pre&gt;

&lt;p&gt;For now we won't override any of the defaults in our test page, but we'll demonstrate this later.&lt;/p&gt;

&lt;h5&gt;Step 4&lt;/h5&gt;
&lt;p&gt;So that takes care of all the preliminary considerations.  Let's get to coding the  plugin's functionality.  As you've already seen, the plugin is returning &lt;span class="inline_code"&gt;this.each(...)&lt;/span&gt;.  This line will execute the contained anonymous function on each item  in the jQuery array.  So, if for example we called &lt;span class="inline_code"&gt;$(&amp;#39;p&amp;#39;).truncate()&lt;/span&gt;, the code we're about to write would execute on every &lt;span class="inline_code"&gt;p&lt;/span&gt; tag.&lt;/p&gt;

&lt;p&gt;Since I'm assuming a comfortable understanding of jQuery, I won't explain in detail how the function's code actually works.  If anything in the code is not obvious, you should refer to the &lt;a href="http://docs.jquery.com/Main_Page" target="new"&gt;documentation&lt;/a&gt; or ask a question in the comments. To complete your plugin, update it to match the following:&lt;/p&gt;

&lt;pre name="code" class="js"&gt;
(function($){
 $.fn.truncate = function(options) {
    
  var defaults = {
   length: 300,
   minTrail: 20,
   moreText: &amp;quot;more&amp;quot;,
   lessText: &amp;quot;less&amp;quot;,
   ellipsisText: &amp;quot;...&amp;quot;
  };
  
  var options = $.extend(defaults, options);
    
  return this.each(function() {
   obj = $(this);
   var body = obj.html();
   
   if(body.length &amp;gt; options.length + options.minTrail) {
    var splitLocation = body.indexOf(&amp;#39; &amp;#39;, options.length);
    if(splitLocation != -1) {
     // truncate tip
     var splitLocation = body.indexOf(&amp;#39; &amp;#39;, options.length);
     var str1 = body.substring(0, splitLocation);
     var str2 = body.substring(splitLocation, body.length - 1);
     obj.html(str1 + &amp;#39;&amp;lt;span class=&amp;quot;truncate_ellipsis&amp;quot;&amp;gt;&amp;#39; + options.ellipsisText + 
      &amp;#39;&amp;lt;/span&amp;gt;&amp;#39; + &amp;#39;&amp;lt;span  class=&amp;quot;truncate_more&amp;quot;&amp;gt;&amp;#39; + str2 + &amp;#39;&amp;lt;/span&amp;gt;&amp;#39;);
     obj.find(&amp;#39;.truncate_more&amp;#39;).css(&amp;quot;display&amp;quot;, &amp;quot;none&amp;quot;);
     
     // insert more link
     obj.append(
      &amp;#39;&amp;lt;div class=&amp;quot;clearboth&amp;quot;&amp;gt;&amp;#39; +
       &amp;#39;&amp;lt;a href=&amp;quot;#&amp;quot; class=&amp;quot;truncate_more_link&amp;quot;&amp;gt;&amp;#39; +  options.moreText + &amp;#39;&amp;lt;/a&amp;gt;&amp;#39; + 
      &amp;#39;&amp;lt;/div&amp;gt;&amp;#39;
     );

     // set onclick event for more/less link
     var moreLink = $(&amp;#39;.truncate_more_link&amp;#39;, obj);
     var moreContent = $(&amp;#39;.truncate_more&amp;#39;, obj);
     var ellipsis = $(&amp;#39;.truncate_ellipsis&amp;#39;, obj);
     moreLink.click(function() {
      if(moreLink.text() == options.moreText) {
       moreContent.show(&amp;#39;normal&amp;#39;);
       moreLink.text(options.lessText);
       ellipsis.css(&amp;quot;display&amp;quot;, &amp;quot;none&amp;quot;);
      } else {
       moreContent.hide(&amp;#39;normal&amp;#39;);
       moreLink.text(options.moreText);
       ellipsis.css(&amp;quot;display&amp;quot;, &amp;quot;inline&amp;quot;);
      }
      return false;
       });
    }
   } // end if
   
  });
 };
})(jQuery);
&lt;/pre&gt;

&lt;p&gt;You'll notice that whenever I needed to select an element within the plugin, I always used &lt;span class="inline_code"&gt;obj&lt;/span&gt; as my context (e.g., &lt;span class="inline_code"&gt;moreLink = $('.truncate_more_link', obj)&lt;/span&gt;).  This is necessary to constrain any selections to the current truncated element.  Without setting the context like this, you will get unpredictable results.&lt;/p&gt;

&lt;p&gt;So that's it - your first jQuery plugin!  We're not quite finished though, since I promised we'd demonstrate overriding the default options.  In the following example, every option has been over ridden, although it is perfectly valid to override fewer.  Just replace the script in your test page with this: &lt;/p&gt;

&lt;pre name="code" class="xhtml"&gt;
$().ready(function() {
 $(&amp;#39;.tip&amp;#39;).truncate( {
  length: 120,
  minTrail: 10,
  moreText: &amp;#39;show more&amp;#39;,
  lessText: &amp;#39;show less&amp;#39;,
  ellipsisText: &amp;quot; [there&amp;#39;s more...]&amp;quot;
 });
});
&lt;/pre&gt;

&lt;p&gt;This code will give you something like this: &lt;/p&gt;

&lt;div style="text-align:center;margin:15px 0 15px 0;"&gt;
&lt;div id="example2" style="margin-left:auto;margin-right:auto;width:320px;padding:10px;background-color:#EFEFD1;border:1px solid #ccc;text-align:left;"&gt;
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Etiam fringilla, purus a ultrices blandit,
  odio ante scelerisque neque, vitae imperdiet odio velit ac nisl. Sed tortor metus, placerat condimentum,
  feugiat in, feugiat adipiscing, mi. Donec pulvinar sem vitae leo. Vestibulum eget lectus et ligula hendrerit
  pharetra. Sed porta justo ac nisl. Aliquam nisi erat, pellentesque sed, sagittis eu, fringilla sit amet,
  dolor. Nam ac mi. Pellentesque pede purus, mattis aliquet, semper nec, cursus a, orci. Duis bibendum nibh
  ac massa. Integer eu tortor. Aenean convallis quam at nunc. Nunc mollis tincidunt nisi. Suspendisse mauris
  odio, iaculis ut, feugiat vitae, ultrices in, tortor. Quisque at elit. In hac habitasse platea dictumst.
&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Well... I hope you found this helpful.  If you have any questions beyond what I've explained, please just ask in the comments.  Thanks for reading!&lt;/p&gt;

&lt;div class="update"&gt;
  &lt;h5&gt;Update! (2/26/2008)&lt;/h5&gt;
  &lt;p&gt;The plugin that we just developed above has now been added to the jQuery plugin repository under the name of jTruncate.  The home page is located &lt;a href="http://jmar777.blogspot.com/2008/02/jtruncate-text-truncation-for-jquery.html"&gt;here on my blog&lt;/a&gt;.  It is now an evolving beast, so check there for any updates.&lt;/p&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1078898499337496912-3612402992787556312?l=blog.jeremymartin.name' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jeremymartin.name/feeds/3612402992787556312/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1078898499337496912&amp;postID=3612402992787556312' title='70 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/3612402992787556312'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/3612402992787556312'/><link rel='alternate' type='text/html' href='http://blog.jeremymartin.name/2008/02/building-your-first-jquery-plugin-that.html' title='Building Your First jQuery Plugin'/><author><name>Jeremy Martin</name><uri>http://www.blogger.com/profile/03514319709844297772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>70</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1078898499337496912.post-6993261217835864411</id><published>2008-01-31T07:16:00.001-08:00</published><updated>2008-02-08T09:25:19.290-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Politics'/><title type='text'>'08 Candidates and Healthcare</title><content type='html'>&lt;script type="text/javascript"&gt;

/**
 * Copyright (c) 2006 Luke Lutman (http://www.lukelutman.com)
 * Dual licensed under the MIT and GPL licenses.
 **/ 
;(function(){
 
var $$;

$$ = jQuery.fn.flash = function(htmlOptions, pluginOptions, replace, update) {
 
 // Set the default block.
 var block = replace || $$.replace;
 
 // Merge the default and passed plugin options.
 pluginOptions = $$.copy($$.pluginOptions, pluginOptions);
 
 // Detect Flash.
 if(!$$.hasFlash(pluginOptions.version)) {
  // Use Express Install (if specified and Flash plugin 6,0,65 or higher is installed).
  if(pluginOptions.expressInstall &amp;&amp; $$.hasFlash(6,0,65)) {
   // Add the necessary flashvars (merged later).
   var expressInstallOptions = {
    flashvars: {   
     MMredirectURL: location,
     MMplayerType: 'PlugIn',
     MMdoctitle: jQuery('title').text() 
    }     
   };
  // Ask the user to update (if specified).
  } else if (pluginOptions.update) {
   // Change the block to insert the update message instead of the flash movie.
   block = update || $$.update;
  // Fail
  } else {
   // The required version of flash isn't installed.
   // Express Install is turned off, or flash 6,0,65 isn't installed.
   // Update is turned off.
   // Return without doing anything.
   return this;
  }
 }
 
 // Merge the default, express install and passed html options.
 htmlOptions = $$.copy($$.htmlOptions, expressInstallOptions, htmlOptions);
 
 // Invoke $block (with a copy of the merged html options) for each element.
 return this.each(function(){
  block.call(this, $$.copy(htmlOptions));
 });
 
};
/**
 *
 * @name flash.copy
 * @desc Copy an arbitrary number of objects into a new object.
 * @type Object
 * 
 * @example $$.copy({ foo: 1 }, { bar: 2 });
 * @result { foo: 1, bar: 2 };
 *
**/
$$.copy = function() {
 var options = {}, flashvars = {};
 for(var i = 0; i &lt; arguments.length; i++) {
  var arg = arguments[i];
  if(arg == undefined) continue;
  jQuery.extend(options, arg);
  // don't clobber one flash vars object with another
  // merge them instead
  if(arg.flashvars == undefined) continue;
  jQuery.extend(flashvars, arg.flashvars);
 }
 options.flashvars = flashvars;
 return options;
};
/*
 * @name flash.hasFlash
 * @desc Check if a specific version of the Flash plugin is installed
 * @type Boolean
 *
**/
$$.hasFlash = function() {
 // look for a flag in the query string to bypass flash detection
 if(/hasFlash\=true/.test(location)) return true;
 if(/hasFlash\=false/.test(location)) return false;
 var pv = $$.hasFlash.playerVersion().match(/\d+/g);
 var rv = String([arguments[0], arguments[1], arguments[2]]).match(/\d+/g) || String($$.pluginOptions.version).match(/\d+/g);
 for(var i = 0; i &lt; 3; i++) {
  pv[i] = parseInt(pv[i] || 0);
  rv[i] = parseInt(rv[i] || 0);
  // player is less than required
  if(pv[i] &lt; rv[i]) return false;
  // player is greater than required
  if(pv[i] &gt; rv[i]) return true;
 }
 // major version, minor version and revision match exactly
 return true;
};
/**
 *
 * @name flash.hasFlash.playerVersion
 * @desc Get the version of the installed Flash plugin.
 * @type String
 *
**/
$$.hasFlash.playerVersion = function() {
 // ie
 try {
  try {
   // avoid fp6 minor version lookup issues
   // see: http://blog.deconcept.com/2006/01/11/getvariable-setvariable-crash-internet-explorer-flash-6/
   var axo = new ActiveXObject('ShockwaveFlash.ShockwaveFlash.6');
   try { axo.AllowScriptAccess = 'always'; } 
   catch(e) { return '6,0,0'; }    
  } catch(e) {}
  return new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version').replace(/\D+/g, ',').match(/^,?(.+),?$/)[1];
 // other browsers
 } catch(e) {
  try {
   if(navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin){
    return (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]).description.replace(/\D+/g, ",").match(/^,?(.+),?$/)[1];
   }
  } catch(e) {}  
 }
 return '0,0,0';
};
/**
 *
 * @name flash.htmlOptions
 * @desc The default set of options for the object or embed tag.
 *
**/
$$.htmlOptions = {
 height: 240,
 flashvars: {},
 pluginspage: 'http://www.adobe.com/go/getflashplayer',
 src: '#',
 type: 'application/x-shockwave-flash',
 width: 320  
};
/**
 *
 * @name flash.pluginOptions
 * @desc The default set of options for checking/updating the flash Plugin.
 *
**/
$$.pluginOptions = {
 expressInstall: false,
 update: true,
 version: '6.0.65'
};
/**
 *
 * @name flash.replace
 * @desc The default method for replacing an element with a Flash movie.
 *
**/
$$.replace = function(htmlOptions) {
 this.innerHTML = '&lt;div class="alt"&gt;'+this.innerHTML+'&lt;/div&gt;';
 jQuery(this)
  .addClass('flash-replaced')
  .prepend($$.transform(htmlOptions));
};
/**
 *
 * @name flash.update
 * @desc The default method for replacing an element with an update message.
 *
**/
$$.update = function(htmlOptions) {
 var url = String(location).split('?');
 url.splice(1,0,'?hasFlash=true&amp;');
 url = url.join('');
 var msg = '&lt;p&gt;This content requires the Flash Player. &lt;a href="http://www.adobe.com/go/getflashplayer"&gt;Download Flash Player&lt;/a&gt;. Already have Flash Player? &lt;a href="'+url+'"&gt;Click here.&lt;/a&gt;&lt;/p&gt;';
 this.innerHTML = '&lt;span class="alt"&gt;'+this.innerHTML+'&lt;/span&gt;';
 jQuery(this)
  .addClass('flash-update')
  .prepend(msg);
};
/**
 *
 * @desc Convert a hash of html options to a string of attributes, using Function.apply(). 
 * @example toAttributeString.apply(htmlOptions)
 * @result foo="bar" foo="bar"
 *
**/
function toAttributeString() {
 var s = '';
 for(var key in this)
  if(typeof this[key] != 'function')
   s += key+'="'+this[key]+'" ';
 return s;  
};
/**
 *
 * @desc Convert a hash of flashvars to a url-encoded string, using Function.apply(). 
 * @example toFlashvarsString.apply(flashvarsObject)
 * @result foo=bar&amp;foo=bar
 *
**/
function toFlashvarsString() {
 var s = '';
 for(var key in this)
  if(typeof this[key] != 'function')
   s += key+'='+encodeURIComponent(this[key])+'&amp;';
 return s.replace(/&amp;$/, '');  
};
/**
 *
 * @name flash.transform
 * @desc Transform a set of html options into an embed tag.
 * @type String 
 *
 * @example $$.transform(htmlOptions)
 * @result &lt;embed src="foo.swf" ... /&gt;
 *
 * Note: The embed tag is NOT standards-compliant, but it 
 * works in all current browsers. flash.transform can be
 * overwritten with a custom function to generate more 
 * standards-compliant markup.
 *
**/
$$.transform = function(htmlOptions) {
 htmlOptions.toString = toAttributeString;
 if(htmlOptions.flashvars) htmlOptions.flashvars.toString = toFlashvarsString;
 return '&lt;embed ' + String(htmlOptions) + '/&gt;';  
};

/**
 *
 * Flash Player 9 Fix (http://blog.deconcept.com/2006/07/28/swfobject-143-released/)
 *
**/
if (window.attachEvent) {
 window.attachEvent("onbeforeunload", function(){
  __flash_unloadHandler = function() {};
  __flash_savedUnloadHandler = function() {};
 });
}
 
})();
&lt;/script&gt;

&lt;script type="text/javascript"&gt;
$().ready(function() {
 $('.videoLink').click(function() {
  $('#videoHolder').html('');

  candidate = $(this).attr('rel');
  if(candidate == 'obama') {
   f = 'http://cdn.icyou.com/files/flashvideo/2057_3e1640a975961f3b40454b9c29d1d358.flv';
   i = 'http://cdn.icyou.com/files/flashvideo/2057_3e1640a975961f3b40454b9c29d1d358.jpg';
  } else if(candidate == 'romney') {
   f = 'http://cdn.icyou.com/files/flashvideo/2054_c3a17fda0dd8046fa6ea3ffd7c5a3492.flv';
   i = 'http://cdn.icyou.com/files/flashvideo/2054_c3a17fda0dd8046fa6ea3ffd7c5a3492.jpg';
  } else if(candidate == 'mccain') {
   f = 'http://cdn.icyou.com/files/flashvideo/2052_0fbcfc022f0c934c292cfbffc6896dc2.flv';
   i = 'http://cdn.icyou.com/files/flashvideo/2052_0fbcfc022f0c934c292cfbffc6896dc2.jpg';
  } else if(candidate == 'huckabee') {
   f = 'http://cdn.icyou.com/files/flashvideo/2051_817a8b7c5eb5b2dea171898fb2807a24.flv';
   i = 'http://cdn.icyou.com/files/flashvideo/2051_817a8b7c5eb5b2dea171898fb2807a24.jpg';
  } else if(candidate = 'clinton') {
   f = 'http://cdn.icyou.com/files/flashvideo/2047_2e380444f6f08d41b50dfc115711a21e.flv';
   i = 'http://cdn.icyou.com/files/flashvideo/2047_2e380444f6f08d41b50dfc115711a21e.jpg';
  }

  $('#videoHolder').flash(
     { src: 'http://icyou.com/files/flashvideo/flvplayer.swf',
    width: 400,
    height: 320,
    movie: 'http://icyou.com/files/flashvideo/flvplayer.swf',
    wmode: 'transparent',
    flashvars: {file: f, image: i, repeat: 'false', autostart: 'true', logo: 'http://cdn.icyou.com/sites/all/themes/icyou5/images/watermark.png' }
     },
     { version: 8 }
    );
  $('.videoLink').not($(this)).removeClass('current');
  $(this).addClass('current');
  return false;
 });

});
&lt;/script&gt;
&lt;style type="text/css"&gt;
.videoLink {
  display: block;
  float: left;
  padding: 5px;
  margin: 5px 10px 0 0;
  background-color: #eaeaea;
  border: 1px solid #777;
  border-bottom: none;
}
.videoLink:hover {
  background-color: #ccc;
  text-decoration: none;
}
.videoLink.current {
  background-color: #777;
  color: white;
}
&lt;/style&gt;

&lt;p&gt;As the nation looks forward to the upcoming Super Tuesday primaries, many voters are still trying to lock in on their candidate of choice.  Between the political mud slinging and pundit biases, this decision is never an easy one.  Campaign issues this year have been numerous and polarizing - more so than usual. There is one issue in particular that strikes me as deserving more than the relatively scanty media attention that it has received.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Healthcare&lt;/strong&gt; in the '08 election has served as an overused campaign buzzword, but the specifics seem to get overlooked.  By now most everyone has associated some sort of a "socialized, universal coverage" label with the Democratic hopefuls, and a "free market, tax refunds" solution with the Republicans. Though not entirely inaccurate, these blanket statements certainly do not demonstrate a necessary understanding of the intricate differences among this year's campaigners.&lt;/p&gt;

&lt;p&gt;While I certainly have my political leanings, and they will doubtless become apparent if I keep this blog up (yeah for my first post!), this particular entry is intended as a completely neutral "middle man" source for you.  I say "middle man" because the ultimate purpose of this post is to present you with some helpful videos found over at &lt;a href="http://www.icyou.com" target="new"&gt;icyou&lt;/a&gt;.  I suppose some of you might cry blogspam at this, but I feel I've written long enough of a prelude - so lay off :p&lt;/p&gt;
&lt;p&gt;To watch a video, simply click on the candidate's name.  Although there was also a video for Edwards, I removed it from this list due to him dropping out of the race.&lt;/p&gt;
&lt;a href="#" class="videoLink current" rel="obama"&gt;Obama&lt;/a&gt;
&lt;a href="#" class="videoLink" rel="romney"&gt;Romney&lt;/a&gt;
&lt;a href="#" class="videoLink" rel="mccain"&gt;McCain&lt;/a&gt;
&lt;a href="#" class="videoLink" rel="huckabee"&gt;Huckabee&lt;/a&gt;
&lt;a href="#" class="videoLink" rel="clinton"&gt;Clinton&lt;/a&gt;

&lt;div style="clear:both;"&gt;&lt;/div&gt;
&lt;div id="videoHolder" style="width:400px;height:320px;background-color:black;"&gt;
&lt;object width="400" height="320" style="margin-left:auto;margin-right:auto;"&gt;
 &lt;param name="movie" value="http://icyou.com/files/flashvideo/flvplayer.swf" /&gt;
 &lt;param name="wmode" value="transparent" /&gt;
 &lt;param name="FlashVars" value="file=http://cdn.icyou.com/files/flashvideo/2057_3e1640a975961f3b40454b9c29d1d358.flv&amp;image=http://cdn.icyou.com/files/flashvideo/2057_3e1640a975961f3b40454b9c29d1d358.jpg&amp;repeat=false&amp;autostart=false&amp;logo=http://cdn.icyou.com/sites/all/themes/icyou5/images/watermark.png" /&gt;
 &lt;embed src="http://icyou.com/files/flashvideo/flvplayer.swf" flashvars="file=http://cdn.icyou.com/files/flashvideo/2057_3e1640a975961f3b40454b9c29d1d358.flv&amp;image=http://cdn.icyou.com/files/flashvideo/2057_3e1640a975961f3b40454b9c29d1d358.jpg&amp;repeat=false&amp;autostart=false&amp;logo=http://cdn.icyou.com/sites/all/themes/icyou5/images/watermark.png" type="application/x-shockwave-flash" wmode="transparent" width="400" height="320" /&gt;
&lt;/object&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;p&gt;I have tried to present these videos in a convenient manner, but due to compatibility issues the above links might not work for some.  So just in case, here are the direct links:
&lt;a href="http://www.icyou.com/tags/01-front-page/overview-obama-healthcare-reform-plan" target="new"&gt;Obama&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://www.icyou.com/topics/healthcare-policy/overview-romney-healthcare-reform-plan" target="new"&gt;Romney&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://www.icyou.com/topics/healthcare-policy/overview-mccain-healthcare-reform-plan" target="new"&gt;McCain&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://www.icyou.com/topics/healthcare-policy/overview-huckabee-healthcare-reform-plan" target="new"&gt;Huckabee&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://www.icyou.com/topics/healthcare-policy/overview-clinton-healthcare-reform-plan" target="new"&gt;Clinton&lt;/a&gt;&lt;br /&gt;
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1078898499337496912-6993261217835864411?l=blog.jeremymartin.name' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jeremymartin.name/feeds/6993261217835864411/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1078898499337496912&amp;postID=6993261217835864411' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/6993261217835864411'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1078898499337496912/posts/default/6993261217835864411'/><link rel='alternate' type='text/html' href='http://blog.jeremymartin.name/2008/01/copyright-c-2006-luke-lutman-httpwww.html' title='&apos;08 Candidates and Healthcare'/><author><name>Jeremy Martin</name><uri>http://www.blogger.com/profile/03514319709844297772</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
