<?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-5016251368610822667</id><updated>2012-02-16T11:52:10.080Z</updated><category term='packaging'/><category term='postgresql'/><category term='typography'/><category term='mysql'/><category term='web'/><category term='encoding'/><category term='ajax'/><category term='html'/><category term='development'/><category term='latex'/><category term='templating'/><category term='graphics'/><category term='testing'/><category term='oo design'/><title type='text'>SIGSTP</title><subtitle type='html'>On programming in Perl and other random bytes</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://sigstp.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5016251368610822667/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://sigstp.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Jerome Eteve</name><uri>http://www.blogger.com/profile/10262102551420196339</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_KUgWQCbhgu8/TQTtfBPEohI/AAAAAAAABTM/JGfI_NTVyio/S220/bender.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>16</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-5016251368610822667.post-7285544475866266916</id><published>2011-08-24T22:18:00.002+01:00</published><updated>2011-08-25T09:39:21.992+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='latex'/><category scheme='http://www.blogger.com/atom/ns#' term='graphics'/><title type='text'>LaTeX: Included graphics resolution</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;While most graphic files on the internet have a resolution of 72pixel/inch, you need to keep in mind that this resolution is often not suitable for printing. To illustrate that, let's take two images that have the same number of pixels (348 x 350):&lt;br /&gt;&lt;div&gt;One is set at 72pixels/inch:&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-0sp_RLr21BQ/TlVmXIY0FgI/AAAAAAAABcg/ZiT8zyFB2Yg/s1600/lowres.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-0sp_RLr21BQ/TlVmXIY0FgI/AAAAAAAABcg/ZiT8zyFB2Yg/s1600/lowres.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;And the other one is set at 144pixels/inch:&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-U-9QjPUFPv8/TlVmwN8CiiI/AAAAAAAABck/7keskGzV6fU/s1600/highres.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-U-9QjPUFPv8/TlVmwN8CiiI/AAAAAAAABck/7keskGzV6fU/s1600/highres.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;As you can see here, there's no way to tell the difference between them on the screen because your browser displays these images according to their sizes in pixels, regardless of their resolution.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now if you write a LaTeX document that includes them both:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;\documentclass{article}&lt;/div&gt;&lt;div&gt;\usepackage{graphicx}&lt;/div&gt;&lt;div&gt;\begin{document}&lt;/div&gt;&lt;div&gt;\includegraphics{lowres.png}&lt;/div&gt;&lt;div&gt;\includegraphics{highres.png}&lt;/div&gt;&lt;div&gt;\end{document}&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's what you get as the resulting pdf:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-GmsPsqP_bm0/TlVntA3s49I/AAAAAAAABco/YGVyQQr8EWo/s1600/Screenshot-doc.pdf.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="388" src="http://3.bp.blogspot.com/-GmsPsqP_bm0/TlVntA3s49I/AAAAAAAABco/YGVyQQr8EWo/s400/Screenshot-doc.pdf.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;As you can see, the original 72px/in image will appear 'too big', pixelized and blurry on your piece of paper, whereas the 144px/in one will be twice as small and keep its sharpness.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So don't hesitate to experiment with resolution when making LaTeX based documents.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;That's all for today!&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/5016251368610822667-7285544475866266916?l=sigstp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sigstp.blogspot.com/feeds/7285544475866266916/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sigstp.blogspot.com/2011/08/latex-included-graphics-resolution.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5016251368610822667/posts/default/7285544475866266916'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5016251368610822667/posts/default/7285544475866266916'/><link rel='alternate' type='text/html' href='http://sigstp.blogspot.com/2011/08/latex-included-graphics-resolution.html' title='LaTeX: Included graphics resolution'/><author><name>Jerome Eteve</name><uri>http://www.blogger.com/profile/10262102551420196339</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_KUgWQCbhgu8/TQTtfBPEohI/AAAAAAAABTM/JGfI_NTVyio/S220/bender.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-0sp_RLr21BQ/TlVmXIY0FgI/AAAAAAAABcg/ZiT8zyFB2Yg/s72-c/lowres.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5016251368610822667.post-5966127085445040070</id><published>2011-04-02T14:09:00.000+01:00</published><updated>2011-04-02T14:09:34.199+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ajax'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><category scheme='http://www.blogger.com/atom/ns#' term='html'/><title type='text'>Implement Ajax actions using page slices [Part 2]</title><content type='html'>Last time I discussed how to implement Ajax browsing using page slices] generated&lt;br /&gt;at server side. If you haven't read that yet, I strongly encourage you to do so, cause there's little chance the rest of this post will make sense to you.&lt;br /&gt;&lt;br /&gt;Read Part 1- &lt;a href="http://sigstp.blogspot.com/2011/02/slice-your-html-to-ajax-anything.html"&gt;Implement Ajax browsing using page slices&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;This time we're going to apply the same technique, but we'll implement some actions. By actions I mean simple interactions for instance 'vote a comment up', or 'follow a member', 'delete an item' etc.. Any kind of interaction that does not require more than a click from the user in an Ajax interface.&lt;br /&gt;&lt;br /&gt;For instance, on &lt;a href="http://libsquare.net/"&gt;libsquare.net&lt;/a&gt;, if you are logged in, you can vote up or down any review that appear on the &lt;a href="http://libsquare.net/libs/14"&gt;jQuery page&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/--5NzEUcj7Wo/TZcc29QCt3I/AAAAAAAABUg/o1uERgUSlb4/s1600/review_box.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/--5NzEUcj7Wo/TZcc29QCt3I/AAAAAAAABUg/o1uERgUSlb4/s1600/review_box.png" /&gt;&lt;/a&gt;&lt;/div&gt;So how do we implement that?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;The pure HTML flow&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;First let's remember that &lt;a href="http://sigstp.blogspot.com/2011/02/slice-your-html-to-ajax-anything.html"&gt;page slicing&lt;/a&gt; is designed to allow us to implement things without JavaScript, so let's just do that. Here's the work flow of the vote up feature without any JavaScript: &lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-wCx6tKfViSM/TZcdMEjb_II/AAAAAAAABUk/2zef6QCx3PI/s1600/vote_flow.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-wCx6tKfViSM/TZcdMEjb_II/AAAAAAAABUk/2zef6QCx3PI/s1600/vote_flow.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;The user clicks on vote up, he arrives on a page where the vote up is pre-selected, clicks submit and is redirected to the page review with the vote count updated.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Let's Ajax this!&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;First let's give a class 'do_vote_up' to our vote up link:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;lt;a href=".../review/111/vote_up" class="do_vote_up"&amp;gt;Vote up&amp;lt;/a&amp;gt;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;br /&gt;Then we need to give an ID and slice the container that contains the voting unit:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;lt;div class="slice_container" id="review_vote_111"&amp;gt;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;lt;&amp;amp; /slice.mas , id =&amp;gt; 'review_vote_111' &amp;amp;&amp;gt;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;... Your vote display html code ...&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;lt;a href=".../review/111/vote_up" class="do_vote_up"&amp;gt;Vote up&amp;lt;/a&amp;gt;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;...&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;lt;/&amp;amp;&amp;gt;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Let's assume /review/111 is a page that always display the review with it's voting part.&lt;br /&gt;&lt;br /&gt;Now we're only a small bit of Javascript away from the full Ajaxed feature:&lt;br /&gt;&lt;div style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;$('a.do_vote_up').live('click', function(event){&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp; event.preventDefault();&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp; var a = $(event.target);&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp; var container = a.closest('.slice_container');&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp; var target_url = a.attr('href');&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp; var result_url = target_url; result_url.replace('\/vote_up','');&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp; // Post a vote up query to the voting URL.&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp; $.ajax({&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; type: 'POST',&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; url: target_url,&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; data: { vote: 1 , vote_submit : 1 },&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; success: function(){&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // On success, reload the voting slice that now contains the updated vote.&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; container.load(result_url,{ page_slice: container.attr('id') });&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp; });&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;});&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Et voila, the vote up action is now Ajaxed. Implementing the same thing for the vote down is left as an exercise for the reader :P&lt;br /&gt;&lt;br /&gt;Next time I'll be speaking about submitting forms and dealing with redirections in Ajax. Stay tuned and thanks for reading!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5016251368610822667-5966127085445040070?l=sigstp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sigstp.blogspot.com/feeds/5966127085445040070/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sigstp.blogspot.com/2011/04/implement-ajax-actions-using-page.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5016251368610822667/posts/default/5966127085445040070'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5016251368610822667/posts/default/5966127085445040070'/><link rel='alternate' type='text/html' href='http://sigstp.blogspot.com/2011/04/implement-ajax-actions-using-page.html' title='Implement Ajax actions using page slices [Part 2]'/><author><name>Jerome Eteve</name><uri>http://www.blogger.com/profile/10262102551420196339</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_KUgWQCbhgu8/TQTtfBPEohI/AAAAAAAABTM/JGfI_NTVyio/S220/bender.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/--5NzEUcj7Wo/TZcc29QCt3I/AAAAAAAABUg/o1uERgUSlb4/s72-c/review_box.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5016251368610822667.post-6960541662015712660</id><published>2011-02-21T20:20:00.002Z</published><updated>2011-04-02T13:14:46.962+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='templating'/><category scheme='http://www.blogger.com/atom/ns#' term='ajax'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Slice your HTML to Ajax anything. [Part 1]</title><content type='html'>There's roughly two ways of addressing Ajax on your website:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Designing your pages with Ajax in mind. &lt;/b&gt;This usually means you'll have a &amp;nbsp;growing number of features&amp;nbsp;that require JavaScript to work. The &lt;a href="http://www.w3.org/TR/WAI-WEBCONTENT/#gl-new-technologies"&gt;W3C recommendation&lt;/a&gt;&amp;nbsp;specifies that you should provide JavaScript-less versions of your features.&amp;nbsp;So it means you will have to develop your features twice to maintain accessibility. Sounds a painful thing to do.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Designing your pages without Ajax in mind&lt;/b&gt;. This means you design only good old pure html/params &amp;amp; forms techniques to&amp;nbsp;animate your features. This is good for accessibility, this is good for testability, this is good for search engines because&amp;nbsp;all your features are accessible via plain links. The only problem is... well there's no Ajax coolness.&lt;/li&gt;&lt;/ul&gt;But we're going to fix that, and it's not going to be painful at all providing you:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;have got zero business logic in your rendering layer. Meaning each part of it is idempotent.&amp;nbsp;This is hopefully the case when you use a MVC model for your application.&lt;/li&gt;&lt;li&gt;use a rendering layer that's capable of manipulating its buffer, and renders the whole page in this buffer before sending it.&lt;/li&gt;&lt;/ul&gt;For this post, I'll be using &lt;a href="http://www.catalystframework.org/"&gt;Catalyst&lt;/a&gt; as the MVC and &lt;a href="http://www.masonhq.com/"&gt;HTML::Mason&lt;/a&gt; as the View layer. We'll focus on implementing Ajax results paging.&amp;nbsp;(Other ajax aspects will be dealt with in later posts).&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Principle of ajax page slices.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The idea of page slices came to me when I was looking at&lt;a href="http://api.jquery.com/load/"&gt; jQuery's load function&lt;/a&gt;. It's got a very convenient trick called 'load page fragments' that allows you to do stuff like:&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;$('#container').load('page_url?offset=2 #result_id');&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;It will look for an element having the id&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt; 'result_id'&lt;/span&gt; in the returned document and replace the content of #container with it. Here's a full example of html/javascript that implements this:&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;lt;div class="container"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;lt;div class="result" id="result_id"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;lt;p&amp;gt;This is page 1&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;lt;p&amp;gt;item 1&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;lt;p&amp;gt;item 2&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;lt;a class="page" href="page_url?page=2"&amp;gt;Go to page 2&amp;lt;/a&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;$(document).ready(function(){&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;$('a.page').live('click',function(e){&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;var a = $(e.target);&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;var result = a.closest('.result');&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;var container = result.closest('.container');&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;container.load(a.attr('href') + ' #' + result.attr('id'));&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;});&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;});&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This does the trick on the client size but it doesn't save much time on the server side.&lt;br /&gt;Plus it requires DOM parsing of the whole document to find the result_id element. Altogether, chances are that your ajax paging will be slower that a simple whole page reload. To fix that, we're going make the server output only the required slice for us.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Let the server do the work.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;First let's have a look first at the intended client side code:&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;lt;div class="container" id="result_id"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;lt;!-- This is the slice 'result_id' --&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;lt;p&amp;gt;This is page 1&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;lt;p&amp;gt;item 1&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;lt;p&amp;gt;item 2&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;lt;a class="page" href="page_url?page=2"&amp;gt;Go to page 2&amp;lt;/a&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;lt;!-- End of slice --&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;$(document).ready(function(){&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;$('a.page').live('click',function(e){&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;var a = $(e.target);&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;var container = result.closest('.container');&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;container.load(a.attr('href'), { page_slice: container.attr('id') });&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;});&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;});&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;On the server side, we need a technique to output only the required slice, discarding any previously generated HTML, and aborting the rendering so no more subsequent HMTL is rendered. In Mason, this is easily done by implementing a content wrapping component.&lt;br /&gt;Here's how it looks in under Catalyst (the &lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;$c &lt;/span&gt;bit):&lt;br /&gt;&lt;br /&gt;Component &lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;page_slice.mas&lt;/span&gt;:&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;lt;%args&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;$slice_id&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;lt;/%args&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;lt;%init&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;my $requested_slice = $c-&amp;gt;req-&amp;gt;param('page_slice');&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;if( ( $requested_slice // '' ) eq $slice_id ){&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;# Discard any previously generated content,&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;# output the content and finish rendering&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;$m-&amp;gt;clear_buffer();&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;$m-&amp;gt;out_method-&amp;gt;($m-&amp;gt;content);&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;$m-&amp;gt;abort();&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;}else{&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;# This component is transparent&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;$m-&amp;gt;out_method-&amp;gt;($m-&amp;gt;content);&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;}&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;lt;/%init&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Here's how to use this component in your &lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;page.mas&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;% deal with param('page') to compute results and next page.&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;lt;div class="container" id="result_id"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;lt;&amp;amp;| /page_slice.mas , slice_id =&amp;gt; 'result_id' &amp;amp;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;lt;!-- This is the slice 'result_id' --&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;% # Output the right results&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;% ...&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;lt;a class="page" href="page_url?page=&amp;lt;% $next_page %&amp;gt;"&amp;gt;Go to page &amp;lt;% $next_page %&amp;gt;&amp;lt;/a&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;lt;!-- End of slice --&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;lt;/&amp;amp;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;$(document).ready(function(){&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;$('a.page').live('click',function(e){&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;var a = $(e.target);&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;var container = result.closest('.container');&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;// Use the container ID as the slice ID.&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;container.load(a.attr('href'), { page_slice: container.attr('id') });&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;});&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp;});&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;When clicking a '.page' link, a request will be sent with the param 'page_slice'. Thanks to this, the component page_slice.mas will output only the requested page slice, and this will populate the container.&lt;br /&gt;&lt;br /&gt;Your paging will obviously works without JavaScript. There's no Ajax specific code at server side. This is:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Good for &lt;b&gt;accessibility&lt;/b&gt;. Try using your paging with lynx. It just works.&lt;/li&gt;&lt;li&gt;Good for &lt;b&gt;SEO&lt;/b&gt;. Our beloved search engines will crawl these links, even if they don't do Ajax.&lt;/li&gt;&lt;li&gt;Good for &lt;b&gt;testing&lt;/b&gt;. Because Ajax is not needed to use your application, you can easily unit test your features from your web test suite.&lt;/li&gt;&lt;li&gt;Good for &lt;b&gt;reliability&lt;/b&gt;. If for some reason your JavaScript is broken, the feature will still be available.&lt;/li&gt;&lt;/ul&gt;Of course this technique can be applied to any kind of browsing features: sorting, faceting etc..&lt;br /&gt;Next time we'll discuss performing an action in Ajax, and managing Ajax redirections.&lt;br /&gt;&lt;br /&gt;I hope you enjoyed this post, thanks for reading!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5016251368610822667-6960541662015712660?l=sigstp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sigstp.blogspot.com/feeds/6960541662015712660/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sigstp.blogspot.com/2011/02/slice-your-html-to-ajax-anything.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5016251368610822667/posts/default/6960541662015712660'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5016251368610822667/posts/default/6960541662015712660'/><link rel='alternate' type='text/html' href='http://sigstp.blogspot.com/2011/02/slice-your-html-to-ajax-anything.html' title='Slice your HTML to Ajax anything. [Part 1]'/><author><name>Jerome Eteve</name><uri>http://www.blogger.com/profile/10262102551420196339</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_KUgWQCbhgu8/TQTtfBPEohI/AAAAAAAABTM/JGfI_NTVyio/S220/bender.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5016251368610822667.post-8303290218648090119</id><published>2011-02-21T14:15:00.002Z</published><updated>2011-03-10T10:58:41.571Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='encoding'/><title type='text'>Avoiding encoding headache</title><content type='html'>&lt;div style="font-family: inherit;"&gt;&lt;span class="Apple-style-span" style="font-size: small; line-height: 18px;"&gt;David Wheeler recently posted about &lt;a href="http://www.justatheory.com/computers/programming/perl/encoding-is-a-headache.html"&gt;encoding headaches&lt;/a&gt;. I'm not going to copy/paste my reply here, but the crux of it is:&lt;/span&gt;&lt;/div&gt;&lt;div style="font-family: inherit;"&gt;&lt;span class="Apple-style-span" style="font-size: small; line-height: 18px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="font-family: inherit;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="line-height: 18px;"&gt;Encoding is for i/o;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: small; line-height: 18px;"&gt;in the Perl space, text must be Perl character strings.&lt;/span&gt;&lt;/div&gt;&lt;div style="font-family: inherit;"&gt;&lt;span class="Apple-style-span" style="font-size: small; line-height: 18px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="font-family: inherit;"&gt;&lt;span class="Apple-style-span" style="font-size: small; line-height: 18px;"&gt;I repeat:&lt;/span&gt;&lt;/div&gt;&lt;div style="font-family: inherit;"&gt;&lt;span class="Apple-style-span" style="font-size: small; line-height: 18px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="font-family: inherit;"&gt;&lt;span class="Apple-style-span" style="font-size: small; line-height: 18px;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="font-family: inherit; line-height: normal; margin: 0px;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="line-height: 18px;"&gt;Encoding is for i/o;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: small; line-height: 18px;"&gt;in the Perl space, text must be Perl character strings.&lt;/span&gt;&lt;/div&gt;&lt;div style="font-family: inherit;"&gt;&lt;span style="font-size: small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="font-family: inherit;"&gt;&lt;span style="font-size: small;"&gt;Write that 100 times, display it next to your monitor(s), record it and play it whilst sleeping on your ipod for one week, have it tattooed on your fingers, and in no time you'll be known as the encoding guru in your company.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,Helvetica,Arial,sans-serif; font-size: 14px; line-height: 18px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5016251368610822667-8303290218648090119?l=sigstp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sigstp.blogspot.com/feeds/8303290218648090119/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sigstp.blogspot.com/2011/02/avoiding-encoding-headache.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5016251368610822667/posts/default/8303290218648090119'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5016251368610822667/posts/default/8303290218648090119'/><link rel='alternate' type='text/html' href='http://sigstp.blogspot.com/2011/02/avoiding-encoding-headache.html' title='Avoiding encoding headache'/><author><name>Jerome Eteve</name><uri>http://www.blogger.com/profile/10262102551420196339</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_KUgWQCbhgu8/TQTtfBPEohI/AAAAAAAABTM/JGfI_NTVyio/S220/bender.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5016251368610822667.post-7193309026615572586</id><published>2011-02-07T17:51:00.002Z</published><updated>2011-03-10T10:58:51.453Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><title type='text'>Some say MySQL does not have any sequences</title><content type='html'>Not true, it's got only one, and it's per session:&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;select last_insert_id(last_insert_id() + 1);&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;To be reset like that:&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;select last_insert_id(0);&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5016251368610822667-7193309026615572586?l=sigstp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sigstp.blogspot.com/feeds/7193309026615572586/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sigstp.blogspot.com/2011/02/some-say-mysql-does-not-have-any.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5016251368610822667/posts/default/7193309026615572586'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5016251368610822667/posts/default/7193309026615572586'/><link rel='alternate' type='text/html' href='http://sigstp.blogspot.com/2011/02/some-say-mysql-does-not-have-any.html' title='Some say MySQL does not have any sequences'/><author><name>Jerome Eteve</name><uri>http://www.blogger.com/profile/10262102551420196339</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_KUgWQCbhgu8/TQTtfBPEohI/AAAAAAAABTM/JGfI_NTVyio/S220/bender.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5016251368610822667.post-4411916410728570765</id><published>2011-02-01T12:01:00.063Z</published><updated>2011-03-10T10:59:02.366Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='development'/><title type='text'>A few difficult things in application development</title><content type='html'>Here are some thoughts I had about developing applications over the last months.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Maintaining documentation&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Yeah I know what you think: nobody reads it, waste of time. People just click everywhere and see what it does. This is probably true for most of the geeks, but observing my parents using a computer taught me &amp;nbsp;you need to document your application features. At least the less obvious ones.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Error reporting&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The same way you can judge a restaurant by the look of its toilets, you can judge an application by the way it deals with errors. It's often a taboo subject, but every single customer will use it sooner or later (sooner in general). Give your application a first class feel: Implement error catching/reporting sensibly.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Making stuff contextual&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This is an empirical law of application development: Whatever the complexity of the system is, there will always be a client saying 'Nice but if &amp;lt;a potentially always false large predicate)&amp;gt;, then the behaviour should be &amp;lt;something crazy no one will understand in one month time&amp;gt;'. At this point, this is an occasion to:&lt;br /&gt;- Add nasty 'if' statements to the appropriate palces and slowly but surely f***-up your beautiful codebase. The client will be happy.&lt;br /&gt;- Or refactor your application to implement this new stuff in an elegant way. This will take longer. The client will be happy - eventually.&lt;br /&gt;&lt;br /&gt;In short: You're doomed.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Moving from single to multiple&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Another empirical law of application development: Whatever you think should be unique will eventually need to be multiple. If you think about it, in nature there's no absolute 1-1 relationships between entities but only probabilities differences. For instance the likelihood of you having one nose is higher than the likelihood of you having one arm. Design for multiple stuff from the beginning to save you some pain in the future.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Complying with unicode.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Complying with unicode is at heart a simple matter of understanding that 'an encoding of the data', 'the data itself' and the 'glyphs to represent it on a piece of screen|paper' are different things. Unfortunately this is still challenging to get for a lot of P* language programmers. If you're used to "print whatever" assuming it "just works" in your english language environment, it's very likely you're wrong.&lt;br /&gt;&lt;br /&gt;More thoughts to come in the future!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5016251368610822667-4411916410728570765?l=sigstp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sigstp.blogspot.com/feeds/4411916410728570765/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sigstp.blogspot.com/2011/02/difficult-things-in-development.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5016251368610822667/posts/default/4411916410728570765'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5016251368610822667/posts/default/4411916410728570765'/><link rel='alternate' type='text/html' href='http://sigstp.blogspot.com/2011/02/difficult-things-in-development.html' title='A few difficult things in application development'/><author><name>Jerome Eteve</name><uri>http://www.blogger.com/profile/10262102551420196339</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_KUgWQCbhgu8/TQTtfBPEohI/AAAAAAAABTM/JGfI_NTVyio/S220/bender.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5016251368610822667.post-3714218838388002420</id><published>2011-01-07T17:11:00.001Z</published><updated>2011-03-10T10:59:23.678Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='typography'/><title type='text'>Fonts: Find font files by font family name</title><content type='html'>Sometime you want to use a piece of software or a library, such as &amp;nbsp;&lt;a href="http://libsquare.net/libs/31"&gt;Imager Graph&lt;/a&gt; are not linked to the &lt;a href="http://www.freedesktop.org/wiki/Software/fontconfig"&gt;fontconfig lib&lt;/a&gt;. Because of that, you can't specify fonts by simply using their family name (Like 'FreeSerif' for instance).&lt;br /&gt;&lt;br /&gt;So you need a way to resolve a font's family name to the full path of the font files on disk. Here's how to do it for the FreeSerif one:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;$ fc-list -f "%{family} %{style[0]} %{file}\n" 'FreeSerif'&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;FreeSerif Bold /usr/share/fonts/truetype/freefont/FreeSerifBold.ttf&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;FreeSerif Medium /usr/share/fonts/truetype/freefont/FreeSerif.ttf&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;FreeSerif Italic /usr/share/fonts/truetype/freefont/FreeSerifItalic.ttf&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;FreeSerif BoldItalic /usr/share/fonts/truetype/freefont/FreeSerifBoldItalic.ttf&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Maybe one day there will be a Perl module bound to the libfontconfig. Until there, a simple system call will probably do for me :)&lt;br /&gt;&lt;br /&gt;&lt;b&gt;EDIT&lt;/b&gt; 31st Jan 2011:&lt;br /&gt;&lt;br /&gt;There's no -f option in older systems, you can also use&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;$ fc-list &amp;nbsp;'FreeSerif' file&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;/usr/share/fonts/truetype/freefont/FreeSerifBoldItalic.ttf:&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;/usr/share/fonts/truetype/freefont/FreeSerif.ttf:&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;/usr/share/fonts/truetype/freefont/FreeSerifBold.ttf:&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;/usr/share/fonts/truetype/freefont/FreeSerifItalic.ttf:&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5016251368610822667-3714218838388002420?l=sigstp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sigstp.blogspot.com/feeds/3714218838388002420/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sigstp.blogspot.com/2011/01/fonts-find-font-files-by-font-family.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5016251368610822667/posts/default/3714218838388002420'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5016251368610822667/posts/default/3714218838388002420'/><link rel='alternate' type='text/html' href='http://sigstp.blogspot.com/2011/01/fonts-find-font-files-by-font-family.html' title='Fonts: Find font files by font family name'/><author><name>Jerome Eteve</name><uri>http://www.blogger.com/profile/10262102551420196339</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_KUgWQCbhgu8/TQTtfBPEohI/AAAAAAAABTM/JGfI_NTVyio/S220/bender.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5016251368610822667.post-1037234124790347447</id><published>2011-01-06T11:13:00.000Z</published><updated>2011-03-10T10:59:52.500Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='development'/><category scheme='http://www.blogger.com/atom/ns#' term='templating'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Perl: Avoiding the HTML::Mason/TemplateToolkit schism</title><content type='html'>As a Perl web developer, I've been using HTML::Mason intensely for many projects. Over the past year, I've also been working with Template Toolkit as a rendering layer for a web application.&lt;br /&gt;&lt;br /&gt;As always, choosing between two similar technologies seems to be mainly a matter of taste and yet another occasion for an holy war. To pacify the situation, let's try to figure out what are these beasts good at.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;TT feels more simple.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Consider the following code: &lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;[% IF customer.is_in('GB') %]&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;We'll ship your order by Royal Mail&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;[% ELSE %]&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Sorry [% customer.firstname %], delivery will take a while.&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;[% END %]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;It's much easier to understand for a non-programmer than the Mason equivalent:&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;% if ( $customer-&amp;gt;is_in('GB') ) {&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;We'll ship your order by Royal Mail&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;% } else {&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Sorry &amp;lt;% $customer-&amp;gt;firstname() %&amp;gt; ...&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;% }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;So here clearly, TT wins, although as a programmer, and specially as a Perl programmer, Mason also feels just fine. However, a designer or a configuration person will feel more at home with TT, as it resembles infamous visual basic excel macros.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Mason simplifies page composition.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Let's implement a set of pages, each with a specific title and content, but with the same structure (here just a navigation box). In fact the common bread of web development&lt;br /&gt;&lt;br /&gt;Let's do it in HTML::Mason:&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;autohandler:&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;lt;head&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;lt;title&amp;gt;&amp;lt;&amp;amp; SELF:title &amp;amp;&amp;gt;&amp;lt;/title&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;lt;/head&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;lt;body&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;lt;div id="nav_box"&amp;gt;...&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;lt;div id="payload"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;% $m-&amp;gt;call_next();&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;lt;/body&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;lt;%method title&amp;gt;A default title&amp;lt;/%method&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;content1.html:&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;lt;p&amp;gt;content 1&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;lt;%method title&amp;gt;Page Content 1&amp;lt;/%method&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;content2.html&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;lt;p&amp;gt;content 2&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;lt;%method title&amp;gt;Page Content 2&amp;lt;/%method&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;etc..&lt;br /&gt;&lt;br /&gt;Now let's do it TT:&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;page:&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;lt;head&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;lt;title&amp;gt;[% title || 'A default title' %]&amp;lt;/title&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;lt;/head&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;lt;body&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;lt;div id="nav_box"&amp;gt;...&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;lt;div id="payload"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;nbsp;[% content %]&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;lt;/body&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;content1.html:&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;[%WRAPPER page&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;title = 'Page content 1'&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;%]&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;lt;p&amp;gt;content 1&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;[%END%]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;content2.html:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;[%WRAPPER page&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;title = 'Page content 2'&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;%]&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;lt;p&amp;gt;content 2&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;[%END%]&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;From a programmer's point of view, HTML::Mason wins, as its inheritance mechanism allows much better simplicity, elegance and flexibility in page composition. In this example, I only considered a simple example that's possible to implement both in Mason and in TT, but for more advance use, the inheritance mechanisms (with call to PARENT (super) methods), and other Mason-isms largely beat the TT WRAPPER directive.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;❧&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;From these two simple examples, it appears that HTML::Mason has got much more to offer to programmers, as it allows them to use Perl natively, use a fairly complete inheritance mechanism, and much more. On the other hand, what TT has to offer is definitely an easier and&amp;nbsp;simpler solution for simple templating jobs.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;To sum up:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;- Use Mason where you need elegance and simplicity to build complex things.&lt;br /&gt;&lt;br /&gt;- Use TT where the 'easier than Perl' feel is important, with a restricted set of directive to build simple things.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5016251368610822667-1037234124790347447?l=sigstp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sigstp.blogspot.com/feeds/1037234124790347447/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sigstp.blogspot.com/2011/01/perl-avoiding-htmlmasontemplatetoolkit.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5016251368610822667/posts/default/1037234124790347447'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5016251368610822667/posts/default/1037234124790347447'/><link rel='alternate' type='text/html' href='http://sigstp.blogspot.com/2011/01/perl-avoiding-htmlmasontemplatetoolkit.html' title='Perl: Avoiding the HTML::Mason/TemplateToolkit schism'/><author><name>Jerome Eteve</name><uri>http://www.blogger.com/profile/10262102551420196339</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_KUgWQCbhgu8/TQTtfBPEohI/AAAAAAAABTM/JGfI_NTVyio/S220/bender.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5016251368610822667.post-7101301788001397695</id><published>2010-11-30T10:03:00.000Z</published><updated>2011-03-10T11:00:32.997Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='development'/><category scheme='http://www.blogger.com/atom/ns#' term='oo design'/><title type='text'>Perl: Separating the persistence and the business model layers - Part 1</title><content type='html'>Today, thanks to &lt;a href="http://www.onyxneon.com/books/modern_perl/index.html"&gt;modern Perl technologies&lt;/a&gt; a growing number of Perl project use DBIx::Class to access the database, and a MVC engine, such as Catalyst or other frameworks and a nice template engine to expose the application on the web. Usually,&lt;a href="http://search.cpan.org/~zarquon/Catalyst-Manual-5.8005/lib/Catalyst/Manual/Intro.pod#Models"&gt; the framework tutorial &lt;/a&gt;assumes that you will use &lt;a href="http://search.cpan.org/dist/DBIx-Class/"&gt;DBIx::Class&lt;/a&gt; to access and store your objects from your MVC controller. I think this approach is wrong for the following reasons:&lt;br /&gt;&lt;br /&gt;- DBIx::Class is a perfectly fine &lt;a href="http://en.wikipedia.org/wiki/Object-relational_mapping"&gt;ORM mapper&lt;/a&gt; but it's not a business model framework. You can add business code to the result Classes but what happens if you want to migrate some of your stuff to a &lt;a href="http://en.wikipedia.org/wiki/Nosql"&gt;NoSQL storage&lt;/a&gt;? Or change the way some stuff is stored in the DB. Things can and will get ugly.&lt;br /&gt;&lt;br /&gt;- Dbic objects do not provide the flexibility you would need to implement common object oriented patterns. What if you want to use Roles, enforce interfaces, implement your own search facility? You'll eventually get so much application business code in your Dbic object that they will no longer look like dbic objects.&lt;br /&gt;&lt;br /&gt;- Your web framework is directly fed with the ORM model, and because you want to code things quickly, you start putting business code in your controller, and this business code assumes you're using this or that ORM. And the rest will come. Web applications are difficult to test for regressions, especially if they use&amp;nbsp;Ajax. Things will break without being detected before release, you will fix them quickly in your controller, and as time goes on, your shiny new application using modern Perl technologies will end up being as difficult to maintain as a good old CGI&amp;nbsp;mud-ball.&lt;br /&gt;&lt;br /&gt;- What if you want to turn your application into an API? Or if you want to make command line tools for quick administration, or for&amp;nbsp;asynchronous&amp;nbsp;runs? Well you can't. Because the your business logic is scattered everywhere, in all the layers of the application.&lt;br /&gt;&lt;br /&gt;What we end up with this approach is our persistence layer and our MVC layer (and in the worst case our template layer) become polluted with a blob of sloppy hard to maintain business model code. Also the sad thing is that your business code IS your business' added value, so it shouldn't be considered polluting something else. I don't think MVC's and ORM's are designed to be the natural container of your business code. I think they should be kept, and loved, and used for what they are: an easy and fast way of making non-business related code thin and minimalistic.&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_KUgWQCbhgu8/TPTHsKt8gXI/AAAAAAAABTI/uqEeCttGsDE/s1600/stack_blob.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_KUgWQCbhgu8/TPTHsKt8gXI/AAAAAAAABTI/uqEeCttGsDE/s1600/stack_blob.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Blob of business code longing for a home on its own&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;For the development of &lt;a href="http://libsquare.net/"&gt;libsquare.net&lt;/a&gt;, I've designed a reasonably fast and easy solution to this problem. I'll be talking about it in the next part of this sequence.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5016251368610822667-7101301788001397695?l=sigstp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sigstp.blogspot.com/feeds/7101301788001397695/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sigstp.blogspot.com/2010/11/perl-separating-persistence-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5016251368610822667/posts/default/7101301788001397695'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5016251368610822667/posts/default/7101301788001397695'/><link rel='alternate' type='text/html' href='http://sigstp.blogspot.com/2010/11/perl-separating-persistence-and.html' title='Perl: Separating the persistence and the business model layers - Part 1'/><author><name>Jerome Eteve</name><uri>http://www.blogger.com/profile/10262102551420196339</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_KUgWQCbhgu8/TQTtfBPEohI/AAAAAAAABTM/JGfI_NTVyio/S220/bender.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_KUgWQCbhgu8/TPTHsKt8gXI/AAAAAAAABTI/uqEeCttGsDE/s72-c/stack_blob.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5016251368610822667.post-5870212185126822960</id><published>2010-11-05T11:30:00.002Z</published><updated>2011-03-10T11:00:48.540Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='typography'/><category scheme='http://www.blogger.com/atom/ns#' term='latex'/><title type='text'>XeTeX: Breaking long lines of Japanese (and Chinese) text.</title><content type='html'>&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;While LaTeX/XeTeX is very good at hyphenating Latin words, I recently came across the problem of overflowing boxes when attempting to typeset a long paragraph consisting exclusively of&amp;nbsp;&lt;/span&gt;Japanese&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&amp;nbsp;characters:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;母親が育児を放棄した末、大阪市西区のマンションで幼い姉弟が亡くなった事件。多くの住民が異変に気づきながら、児童相談所（児相）に通報したのは１人だけだった。複数の人が通報していれば、児相の危機感も強まったかもしれない。なぜ通報をためらった&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;When you render this with XeTeX, you've got a warning that your hbox is overfull, and the rendered result shows an awful truncated Japanese line:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_KUgWQCbhgu8/TNPmzGqXE3I/AAAAAAAABSs/qBu8dDHFGwE/s1600/Screenshot-3.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="52" src="http://4.bp.blogspot.com/_KUgWQCbhgu8/TNPmzGqXE3I/AAAAAAAABSs/qBu8dDHFGwE/s400/Screenshot-3.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Rendering of an non&amp;nbsp;hyphen-able&amp;nbsp;Japanese line&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;We clearly need to fix this, because most of the time your data will be in the form of a long paragraph without any linebreaks.&lt;br /&gt;&lt;br /&gt;In &lt;a href="http://www.tug.org/texmf-dist/doc/xetex/base/XeTeX-notes.pdf"&gt;XeTeX-notes.pdf&lt;/a&gt;, we learn that we can activate the&amp;nbsp;line-breaking&amp;nbsp;in XeTeX by using:&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;&lt;b&gt;\XeTeXlinebreaklocale"en"&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The locale used doesn't matter much, the important thing is that it activates line breaking for too long lines where the hyphenation mechanism cannot do its job (a long Japanese/Chinese line for instance).&lt;br /&gt;&lt;br /&gt;By adding this to your preamble, here's what you get:&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_KUgWQCbhgu8/TNPpu0VQ-yI/AAAAAAAABSw/UM3ozFEzpg0/s1600/Screenshot-4.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="101" src="http://3.bp.blogspot.com/_KUgWQCbhgu8/TNPpu0VQ-yI/AAAAAAAABSw/UM3ozFEzpg0/s400/Screenshot-4.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;A Japanese paragraph with line breaks.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;Et&amp;nbsp;voilà, lines are broken so all the characters fit in the page width!&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;Ps: Thanks to Google news Japan for providing example data.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5016251368610822667-5870212185126822960?l=sigstp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sigstp.blogspot.com/feeds/5870212185126822960/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sigstp.blogspot.com/2010/11/xetex-breaking-long-lines-of-japanese.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5016251368610822667/posts/default/5870212185126822960'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5016251368610822667/posts/default/5870212185126822960'/><link rel='alternate' type='text/html' href='http://sigstp.blogspot.com/2010/11/xetex-breaking-long-lines-of-japanese.html' title='XeTeX: Breaking long lines of Japanese (and Chinese) text.'/><author><name>Jerome Eteve</name><uri>http://www.blogger.com/profile/10262102551420196339</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_KUgWQCbhgu8/TQTtfBPEohI/AAAAAAAABTM/JGfI_NTVyio/S220/bender.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_KUgWQCbhgu8/TNPmzGqXE3I/AAAAAAAABSs/qBu8dDHFGwE/s72-c/Screenshot-3.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5016251368610822667.post-7859617683080854573</id><published>2010-10-07T11:19:00.000+01:00</published><updated>2011-03-10T11:01:15.614Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='development'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='postgresql'/><title type='text'>Perl Postgresql Test Harness</title><content type='html'>These days, I'm developing &lt;a href="http://github.com/jeteve/pg_cryobit"&gt;pg_cryobit&lt;/a&gt;, a piece of software that'll allow you to manage your PostgreSQL continuous backup strategy with ease.&lt;br /&gt;&lt;br /&gt;I stumbled upon&amp;nbsp;&lt;a href="http://search.cpan.org/dist/Test-postgresql"&gt;Test::postgresql&lt;/a&gt;, and at first I was a bit suspicious about it, given the fact the latest version is not recent and that there's no debian build of it.&lt;br /&gt;&lt;br /&gt;I decided to give it a go anyway. I installed it manually, and only one dependency needed another manual install. The other ones come as a debian packages (This is one reason why I don't quite like to use the cpan shell).&lt;br /&gt;&lt;br /&gt;The tests went smoothly, and in no time I had instances of PostgreSQL ready to test with my own software.&lt;br /&gt;&lt;br /&gt;I definitely recommend using it if you're writing PostgreSQL dependent software.&lt;br /&gt;&lt;br /&gt;Has anyone has experience with the &lt;a href="http://search.cpan.org/dist/Test-mysqld/"&gt;MySQL flavour&lt;/a&gt; of it?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5016251368610822667-7859617683080854573?l=sigstp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sigstp.blogspot.com/feeds/7859617683080854573/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sigstp.blogspot.com/2010/10/perl-postgresql-test-harness.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5016251368610822667/posts/default/7859617683080854573'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5016251368610822667/posts/default/7859617683080854573'/><link rel='alternate' type='text/html' href='http://sigstp.blogspot.com/2010/10/perl-postgresql-test-harness.html' title='Perl Postgresql Test Harness'/><author><name>Jerome Eteve</name><uri>http://www.blogger.com/profile/10262102551420196339</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_KUgWQCbhgu8/TQTtfBPEohI/AAAAAAAABTM/JGfI_NTVyio/S220/bender.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5016251368610822667.post-6446682084331032421</id><published>2010-10-06T13:55:00.003+01:00</published><updated>2011-03-10T11:01:24.072Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='development'/><title type='text'>Bugs: Importance classification</title><content type='html'>Dave Child recently posted&amp;nbsp;&lt;a href="http://www.addedbytes.com/blog/importance-and-priorities/"&gt;his thoughts about bug/feature priorities&lt;/a&gt;&amp;nbsp;and asked for contributions, here's mine :)&lt;br /&gt;&lt;br /&gt;- &lt;b&gt;Blocker&lt;/b&gt;: Prevent any operation on the system to happen.&lt;br /&gt;&lt;br /&gt;For instance, your app server conf file is wrong, so it won't even start. Or there's a syntax error in one of your top template. This should never pass your test phase (if it does, you've got a problem).&lt;br /&gt;&lt;br /&gt;- &lt;b&gt;Critical&lt;/b&gt;: A major feature of the system is broken (or missing in case it's a feature ticket) and prevent the business from operating normally. This should never pass the test phase neither.&lt;br /&gt;&lt;br /&gt;Example: If you've got an e-commerce website, the cart does not work, or the checkout is broken.&lt;br /&gt;&lt;br /&gt;- &lt;b&gt;Normal&lt;/b&gt;: A minor feature of the system does not work, or a major feature doesn't work in a particular case. &amp;nbsp;This could pass the test phase, but it will hurt your reputation.&lt;br /&gt;&lt;br /&gt;For instance, your 'share with a friend' link is broken, or the contact us page doesn't work.&lt;br /&gt;&lt;br /&gt;- &lt;b&gt;Minor&lt;/b&gt;: A subfeature does not work, or a minor feature is broken in a particular case. For instance, redimensioning a textarea doesn't work, failing to provide a valid email in the contact page voids your avatar photo. This could pass the test phase, but only a few of your clients will notice.&lt;br /&gt;&lt;br /&gt;- &lt;b&gt;Trivial&lt;/b&gt;: Do not prevent anything from working correctly, but still cam harm your reputation.&lt;br /&gt;&lt;br /&gt;Example: No feedback to confirm a user has saved its preferences, spelling mistakes, weird ordering etc..&lt;br /&gt;&lt;br /&gt;Using this classification, and if you've got an appropriate test plan, your clients should never be exposed to any bugs more important than Normal, ideally only Minor.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5016251368610822667-6446682084331032421?l=sigstp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sigstp.blogspot.com/feeds/6446682084331032421/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sigstp.blogspot.com/2010/10/bugs-importance-classification.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5016251368610822667/posts/default/6446682084331032421'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5016251368610822667/posts/default/6446682084331032421'/><link rel='alternate' type='text/html' href='http://sigstp.blogspot.com/2010/10/bugs-importance-classification.html' title='Bugs: Importance classification'/><author><name>Jerome Eteve</name><uri>http://www.blogger.com/profile/10262102551420196339</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_KUgWQCbhgu8/TQTtfBPEohI/AAAAAAAABTM/JGfI_NTVyio/S220/bender.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5016251368610822667.post-3604604856768425077</id><published>2010-09-23T10:26:00.000+01:00</published><updated>2011-03-10T11:01:33.924Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><title type='text'>MySQL: Changing the order of a table column</title><content type='html'>&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;In an ideal purely standard SQL world, one should never have to care about the order of a table's columns. But we're not in an ideal world, and sometime we want to change the position of a table column. Here's how to do it:&lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial; font-size: small;"&gt;&lt;span class="Apple-style-span" style="font-size: 13px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial; font-size: small;"&gt;&lt;span class="Apple-style-span" style="font-size: 13px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="font-size: 13px;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;ALTER TABLE mytable MODIFY column_move &amp;lt;WHATEVER TYPE IT IS&amp;gt; &amp;nbsp;AFTER another_column&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="font-size: 13px;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;Note that you need to MODIFY the column with its exact type not to loose any data. Copy/Pasting is your friend here. You can also use BEFORE instead of after.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5016251368610822667-3604604856768425077?l=sigstp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sigstp.blogspot.com/feeds/3604604856768425077/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sigstp.blogspot.com/2010/09/mysql-changing-order-of-table-column.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5016251368610822667/posts/default/3604604856768425077'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5016251368610822667/posts/default/3604604856768425077'/><link rel='alternate' type='text/html' href='http://sigstp.blogspot.com/2010/09/mysql-changing-order-of-table-column.html' title='MySQL: Changing the order of a table column'/><author><name>Jerome Eteve</name><uri>http://www.blogger.com/profile/10262102551420196339</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_KUgWQCbhgu8/TQTtfBPEohI/AAAAAAAABTM/JGfI_NTVyio/S220/bender.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5016251368610822667.post-8962858705297400888</id><published>2010-09-18T14:02:00.000+01:00</published><updated>2011-03-10T11:01:41.621Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='development'/><title type='text'>Version names brainstorming</title><content type='html'>Recently we had a brainstorming session in the office to find ubuntu-style version names for our product. Here's my list of suggestions:&lt;br /&gt;&lt;br /&gt;&lt;div style="margin: 0px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;Anemic Antelope&lt;/div&gt;&lt;div style="margin: 0px;"&gt;Blistering Barnacle&lt;/div&gt;&lt;div style="margin: 0px;"&gt;Crying Crocodile&lt;/div&gt;&lt;div style="margin: 0px;"&gt;Dubious Donkey&lt;/div&gt;&lt;div style="margin: 0px;"&gt;Emotive Elephant&lt;/div&gt;&lt;div style="margin: 0px;"&gt;Fiddling Fugu&lt;/div&gt;&lt;div style="margin: 0px;"&gt;Grumpy Giraffe&lt;/div&gt;&lt;div style="margin: 0px;"&gt;Hairy Haddock&lt;/div&gt;&lt;div style="margin: 0px;"&gt;Introvert Impala&lt;/div&gt;&lt;div style="margin: 0px;"&gt;Jolly Jellyfish&lt;/div&gt;&lt;div style="margin: 0px;"&gt;Kitschy Kitten&lt;/div&gt;&lt;div style="margin: 0px;"&gt;Lubricious Lama&lt;/div&gt;&lt;div style="margin: 0px;"&gt;Mystical Magpie&lt;/div&gt;&lt;div style="margin: 0px;"&gt;Nyctalopic Nautilus&lt;/div&gt;&lt;div style="margin: 0px;"&gt;Operatic Oppossum&lt;/div&gt;&lt;div style="margin: 0px;"&gt;Persistant Pinguin&lt;/div&gt;&lt;div style="margin: 0px;"&gt;Quantitative Quahog&lt;/div&gt;&lt;div style="margin: 0px;"&gt;Refreshing Rodent&lt;/div&gt;&lt;div style="margin: 0px;"&gt;Suspicious Salamander&lt;/div&gt;&lt;div style="margin: 0px;"&gt;Tickling Tiger&lt;/div&gt;&lt;div style="margin: 0px;"&gt;Ultramarine Unicorn&lt;/div&gt;&lt;div style="margin: 0px;"&gt;Voluptuous Vixen&lt;/div&gt;&lt;div style="margin: 0px;"&gt;Witty Wapiti&lt;/div&gt;&lt;div style="margin: 0px;"&gt;Xenomorphic Xenopus&lt;/div&gt;&lt;div style="margin: 0px;"&gt;Yummy Yeti&lt;/div&gt;&lt;div style="margin: 0px;"&gt;Zooming Zebu&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;Sometime, software engineering requires a bit of poetry :)&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5016251368610822667-8962858705297400888?l=sigstp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sigstp.blogspot.com/feeds/8962858705297400888/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sigstp.blogspot.com/2010/09/version-names-brainstorming.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5016251368610822667/posts/default/8962858705297400888'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5016251368610822667/posts/default/8962858705297400888'/><link rel='alternate' type='text/html' href='http://sigstp.blogspot.com/2010/09/version-names-brainstorming.html' title='Version names brainstorming'/><author><name>Jerome Eteve</name><uri>http://www.blogger.com/profile/10262102551420196339</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_KUgWQCbhgu8/TQTtfBPEohI/AAAAAAAABTM/JGfI_NTVyio/S220/bender.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5016251368610822667.post-6621677341267680825</id><published>2010-09-14T11:32:00.000+01:00</published><updated>2011-03-10T11:02:01.127Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='packaging'/><category scheme='http://www.blogger.com/atom/ns#' term='development'/><title type='text'>Perl: How to release a developer only version to CPAN</title><content type='html'>If you're about to release a new module and have some beta testers, it's probably a good idea to release a developer only version first and then switch it to a final version number after your beta testers (that includes you :) ) are happy with it.&lt;br /&gt;&lt;br /&gt;To do that, simply appends the release candidate number at the end of your version number. To release the first dev RC version of version 0.07, simply do:&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;our $VERSION = '0.07_01';&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;In your main package.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;The CPAN will detect it and make your release a dev release only.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5016251368610822667-6621677341267680825?l=sigstp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sigstp.blogspot.com/feeds/6621677341267680825/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sigstp.blogspot.com/2010/09/perl-how-to-release-developer-only.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5016251368610822667/posts/default/6621677341267680825'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5016251368610822667/posts/default/6621677341267680825'/><link rel='alternate' type='text/html' href='http://sigstp.blogspot.com/2010/09/perl-how-to-release-developer-only.html' title='Perl: How to release a developer only version to CPAN'/><author><name>Jerome Eteve</name><uri>http://www.blogger.com/profile/10262102551420196339</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_KUgWQCbhgu8/TQTtfBPEohI/AAAAAAAABTM/JGfI_NTVyio/S220/bender.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5016251368610822667.post-4359878192684584624</id><published>2010-09-13T18:14:00.001+01:00</published><updated>2011-03-10T11:02:13.136Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='typography'/><category scheme='http://www.blogger.com/atom/ns#' term='latex'/><title type='text'>LaTeX: Hyphenate single long words in narrow tabular columns</title><content type='html'>Consider the following LaTeX code:&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;\documentclass{article}&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;\usepackage[english]{babel}&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;\begin{document}&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;\begin{center}&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;\begin{tabular}{ | p{2cm} | l | l | p{5cm} |}&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;\hline&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;Incredibilidable &amp;amp; foo &amp;amp; bar &amp;amp; baz \\&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;\hline&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;\end{tabular}&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;\end{center}&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;\end{document}&lt;/span&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;When you render it, the first column overflows on the second one because 'Incredibilidable' is considered to be the first word of a paragraph, and LaTeX does not hyphenate first words of paragraphs. So here's what you get:&amp;nbsp;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_KUgWQCbhgu8/TI5ZqUYycbI/AAAAAAAABSI/YV9Ytu_oDs4/s1600/Screenshot.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_KUgWQCbhgu8/TI5ZqUYycbI/AAAAAAAABSI/YV9Ytu_oDs4/s320/Screenshot.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;And this doesn't look nice.&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;To fix this, we're going to tell LaTeX our word is no longer the first of the paragraph. To do that, we insert a zero length horizontal space before it:&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;&lt;b&gt;\hspace{0pt}&lt;/b&gt;&lt;/span&gt;Incredibilidable &amp;amp; foo &amp;amp; bar &amp;amp; baz \\&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;The rendering now turns into:&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_KUgWQCbhgu8/TI5bFQY_lTI/AAAAAAAABSQ/DCYbiM_3pyQ/s1600/Screenshot-1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_KUgWQCbhgu8/TI5bFQY_lTI/AAAAAAAABSQ/DCYbiM_3pyQ/s320/Screenshot-1.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Et voila!&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Times New Roman';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Times New Roman';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5016251368610822667-4359878192684584624?l=sigstp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sigstp.blogspot.com/feeds/4359878192684584624/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sigstp.blogspot.com/2010/09/latex-hyphenate-single-long-words-in.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5016251368610822667/posts/default/4359878192684584624'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5016251368610822667/posts/default/4359878192684584624'/><link rel='alternate' type='text/html' href='http://sigstp.blogspot.com/2010/09/latex-hyphenate-single-long-words-in.html' title='LaTeX: Hyphenate single long words in narrow tabular columns'/><author><name>Jerome Eteve</name><uri>http://www.blogger.com/profile/10262102551420196339</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_KUgWQCbhgu8/TQTtfBPEohI/AAAAAAAABTM/JGfI_NTVyio/S220/bender.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_KUgWQCbhgu8/TI5ZqUYycbI/AAAAAAAABSI/YV9Ytu_oDs4/s72-c/Screenshot.png' height='72' width='72'/><thr:total>0</thr:total></entry></feed>
