<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Roam notebook</title><link href="http://roam.be/notebook/atom.xml" rel="self"/><link href="http://roam.be"/><updated>2012-04-07T17:36:44Z</updated><id>http://roam.be</id><entry><title>Five minutes a day, two days per year</title><author><name>Kevin Wetzels</name></author><link href="http://roam.be/notebook/2010/five-minutes-a-day-two-days-per-year.html"/><updated>2010-07-25T15:20:30Z</updated><published>2010-07-25T15:20:30Z</published><id>http://roam.be/notebook/2010/five-minutes-a-day-two-days-per-year.html</id><content type="html">
					
	&lt;div class=&quot;intro&quot;&gt;
		&lt;p&gt;
			&lt;!-- Hyde::Excerpt::Begin --&gt;
			People often hesitate to automate tasks. They reckon that that five-minute-once-a-day-thing doesn&#39;t really eat
			into their time and isn&#39;t worth the trouble of getting something else to do it for them instead.
			&lt;!-- Hyde::Excerpt::End --&gt;
		&lt;/p&gt;
	&lt;/div&gt;
	&lt;p&gt;
		Five minutes a day. It would mean &lt;em&gt;not&lt;/em&gt; rushing to pick up the kids from school. Laying in bed five minutes longer 
		each morning. Doesn&#39;t that sound good? It certainly does to me. Or look at it another way: &lt;strong&gt;five minutes per working 
		day adds up to about 20 hours per year&lt;/strong&gt;, or about two and a half days of working. Wouldn&#39;t it be great to have an extra two days 
		to do some &lt;em&gt;real work&lt;/em&gt;, or two more days&amp;nbsp;off?
	&lt;/p&gt;
	&lt;h2&gt;Decide what&#39;s important to&amp;nbsp;you&lt;/h2&gt;
	&lt;p&gt;
		Do yourself a favor and take some time to list your working day and look for the &quot;low-hanging fruit&quot;. Write down all those 
		dirty, boring little tasks and when you&#39;re done, get a developer you trust to have a look at it and let him pick out the 
		stuff that can be automated with&amp;nbsp;ease.
	&lt;/p&gt;
	&lt;p&gt;
		Before you know it you&#39;ll have something cheap that can perform those tasks by itself, leaving you your precious time with 
		family and friends, doing more interesting&amp;nbsp;things.
	&lt;/p&gt;

				</content></entry><entry><title>The value of one-man-shops</title><author><name>Kevin Wetzels</name></author><link href="http://roam.be/notebook/2010/the-value-of-one-man-shops.html"/><updated>2010-07-24T18:20:30Z</updated><published>2010-07-24T18:20:30Z</published><id>http://roam.be/notebook/2010/the-value-of-one-man-shops.html</id><content type="html">
					
	&lt;div class=&quot;intro&quot;&gt;
		&lt;p&gt;
			&lt;!-- Hyde::Excerpt::Begin --&gt;
			Businesses often shy away from hiring freelancers for a job. They might have valid reasons to do so,
			but as a freelancer myself, I mostly see benefits to hiring people like me.
			&lt;!-- Hyde::Excerpt::End --&gt;
		&lt;/p&gt;
	&lt;/div&gt;
	&lt;p&gt;
		You see, a freelancer doesn&#39;t have to rely on &lt;em&gt;someone else&lt;/em&gt; to tell him exactly what you, the customer,
		expects to get out of the project; he&#39;s right beside you every step of the way. He knows. And that&#39;s
		just the start. Contrary to big companies you know exactly who&#39;s working hard on delivering the goods.
		Got a question? Get an answer directly from the source. Got a request? Same thing. There&#39;s no need to
		do the hokey-pokey and wait for your contact to get the time to have a look at your e-mail, pass the
		question on and finally get back to you 2 days later with an&amp;nbsp;answer.
	&lt;/p&gt;
	&lt;h2&gt;It all boils down to&amp;nbsp;this&lt;/h2&gt;
	&lt;p&gt;
		You could write a book about the advantages and disadvantages of hiring a freelancer to build your next
		website or web application, but I feel the entire discussion can be reduced to the following&amp;nbsp;images.
	&lt;/p&gt;
	&lt;h3&gt;The&amp;nbsp;freelancer&lt;/h3&gt;
	&lt;img src=&quot;/media/img/notebook/minivan.jpg&quot; width=&quot;560&quot; height=&quot;284&quot; alt=&quot;Freelancers are like minivans&quot;&gt;
	&lt;p&gt;
		A freelancer is smaller, nimbler, more &quot;agile&quot;. He can park in front of your door, load your stuff in the 
		back and deliver the goods in a timely fashion. Like the driver of a&amp;nbsp;van.
	&lt;/p&gt;
	&lt;h3&gt;The&amp;nbsp;company&lt;/h3&gt;
	&lt;img src=&quot;/media/img/notebook/truck.jpg&quot; width=&quot;560&quot; height=&quot;258&quot; alt=&quot;Big companies are like big trucks&quot;&gt;
	&lt;p&gt;
		The company more closely resembles a truck. Depending on the size of your business it&#39;s already a bit
		of a hassle to get them to come over and find a spot and you better have something large to put
		in the back or you&#39;re not even worth looking at. Of course, it &lt;em&gt;is&lt;/em&gt; a bit pricey since there are more
		mouths to&amp;nbsp;feed.
	&lt;/p&gt;
	&lt;h3&gt;The&amp;nbsp;choice&lt;/h3&gt;
	&lt;p&gt;
		Got something big? Then only a truck will probably do. But for anything that fits the back of a delivery van,
		just get someone with a delivery van to help you out. It&#39;s faster, it&#39;s cheaper. If you&#39;re not sure about the 
		size of your &lt;del&gt;load&lt;/del&gt; project, ask a person who&#39;s judgement you trust to tell you what he thinks 
		about it. Hell, &lt;a href=&quot;#contact&quot;&gt;ask me&lt;/a&gt;.
	&lt;/p&gt;

				</content></entry><entry><title>Django 1.2 upgrade: unique_error_message</title><author><name>Kevin Wetzels</name></author><link href="http://roam.be/notebook/2010/django-1.2-upgrade-unique-error-message.html"/><updated>2010-06-19T11:03:21Z</updated><published>2010-06-19T11:03:21Z</published><id>http://roam.be/notebook/2010/django-1.2-upgrade-unique-error-message.html</id><content type="html">
					
	&lt;div class=&quot;intro&quot;&gt;
		&lt;p&gt;
			&lt;!-- Hyde::Excerpt::Begin --&gt;
			While upgrading a project from Django 1.1 to Django 1.2 everything went flawless. Well, expect this one thing...
			&lt;!-- Hyde::Excerpt::End --&gt;
		&lt;/p&gt;
	&lt;/div&gt;
	&lt;p&gt;
		In Django 1.1 you could customize the error messages for unique constraints over multiple fields by overriding 
		&lt;code&gt;unique_error_message&lt;/code&gt; in your form. In Django 1.2 much of the validation has been moved to the model, including 
		the &lt;code&gt;unique_error_message&lt;/code&gt; checks.
	&lt;/p&gt;
	&lt;p&gt;
		Using Django 1.1 you&#39;d use following code in your &lt;em&gt;form class&lt;/em&gt;:
	&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;unique_error_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;  
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;field&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;field1&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;field2&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;  
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;You should not do that&amp;quot;&lt;/span&gt;  
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MyForm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unique_error_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;
		In Django 1.2 you&#39;ll have to change this to the following code in your &lt;strong&gt;model class&lt;/strong&gt;:
	&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;unique_error_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model_class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;unique_check&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;unique_check&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;field1&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;field2&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;You should not do that&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MyModel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unique_error_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model_class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;unique_check&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


				</content></entry><entry><title>DRY KISS: django-stdfields</title><author><name>Kevin Wetzels</name></author><link href="http://roam.be/notebook/2011/django-stdfields.html"/><updated>2011-11-13T15:30:45Z</updated><published>2011-11-13T15:30:45Z</published><id>http://roam.be/notebook/2011/django-stdfields.html</id><content type="html">
					
    &lt;div class=&quot;intro&quot;&gt;
        &lt;p&gt;
            &lt;!-- Hyde::Excerpt::Begin --&gt;
                Because Django doesn&#39;t really have a model field to track a 
                duration and I always end up inventing something new to make 
                working with &lt;code&gt;choices&lt;/code&gt; on a field easier, I set out
                to finally build a solution that works for me: django-stdfields.
            &lt;!-- Hyde::Excerpt::End --&gt;
        &lt;/p&gt;
    &lt;/div&gt;
    &lt;h2&gt;Duration in&amp;nbsp;Django&lt;/h2&gt;
    &lt;p&gt;
        When you need to record a duration in Django, you&#39;re out of luck using
        a standard Django model field. The &lt;code&gt;DateField&lt;/code&gt;, 
        &lt;code&gt;DateTimeField&lt;/code&gt; and &lt;code&gt;TimeField&lt;/code&gt; do exactly what
        they are supposed to do: record a date, date and time or only the&amp;nbsp;time.
    &lt;/p&gt;
    &lt;p&gt;
        Instead, you could use the model field &lt;code&gt;fields.MinutesField&lt;/code&gt; 
        from django-stdfields. It&#39;s actually a simple extension of Django&#39;s 
        &lt;code&gt;models.PositiveIntegerField&lt;/code&gt; accompanied by a 
        &lt;code&gt;forms.MinutesField&lt;/code&gt; that will allow input in a format most
        users can understand. Instead of other existing third-party solutions,
        the MinutesField does exactly what its name suggests: track 
        &lt;em&gt;minutes&lt;/em&gt;, nothing&amp;nbsp;more.
    &lt;/p&gt;
    &lt;p&gt;
        Users can input &lt;kbd&gt;8:30&lt;/kbd&gt;, resulting in 510 minutes. They can 
        input &lt;kbd&gt;8.5&lt;/kbd&gt; for the same result. Or even &lt;kbd&gt;8,5&lt;/kbd&gt;. Any
        integer value is interpreted as hours spent, any decimal value is 
        interpreted as hours and part of an hour spent and anything of the form
        &lt;code&gt;hh:mm&lt;/code&gt; is interpreted as the number of hours and exact 
        number of minutes spent. It&#39;s basically the way you enter time spent
        on a task in &lt;a href=&quot;http://basecamphq.com/&quot;&gt;Basecamp&lt;/a&gt;.
    &lt;/p&gt;
    &lt;p&gt;
        The tricky part is displaying those minutes back to your users. It&#39;s 
        far easier to interpret &lt;kbd&gt;8:30&lt;/kbd&gt; than &lt;kbd&gt;510&lt;/kbd&gt;. 
        Simple solution: use the included &lt;code&gt;minutes&lt;/code&gt; filter:
    &lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;load&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stdfieldstags&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time_spent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;minutes&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

    &lt;p&gt;
        When &lt;code&gt;task.time_spent&lt;/code&gt; equals 510, this template will print
        &lt;kbd&gt;8:30&lt;/kbd&gt;.
    &lt;/p&gt;
    &lt;h2&gt;Choices in&amp;nbsp;Django&lt;/h2&gt;
    &lt;p&gt;
        The &lt;code&gt;choices&lt;/code&gt; argument for fields is great when you&#39;re 
        dealing with a fixed number of possible values. The thing is... I always
        need to start messing with the constants further down the line. And then
        I need to get the label of the constant. I hate it because it gets 
        gradually harder to find out what the hell you were doing two weeks
        later. The solution:&amp;nbsp;enumerations.
    &lt;/p&gt;
    &lt;p&gt;
        Django-stdfields contains an easy way to create&amp;nbsp;enums:
    &lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.db&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;stdfields.models&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Enum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EnumValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EnumCharField&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CardinalDirection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Enum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;NORTH&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EnumValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;N&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;North&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;EAST&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EnumValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;E&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;East&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;SOUTH&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EnumValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;S&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;South&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;WEST&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EnumValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;W&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;West&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Wind&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;direction&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EnumCharField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;enum&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CardinalDirection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
                            &lt;span class=&quot;n&quot;&gt;max_length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CardinalDirection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;force&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IntegerField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

    &lt;p&gt;
        You could still use a regular &lt;code&gt;models.CharField&lt;/code&gt; and the 
        &lt;code&gt;choices&lt;/code&gt; argument. It&#39;s basically the same thing the
        &lt;code&gt;EnumCharField&lt;/code&gt; and &lt;code&gt;EnumIntegerField&lt;/code&gt; do behind 
        the&amp;nbsp;scenes.
    &lt;/p&gt;
    &lt;p&gt;
        But thanks to the &lt;code&gt;Enumeration&lt;/code&gt; base class, things get easier
        to manage when you have to change stuff around &lt;em&gt;(note: all fields 
        can be used with South)&lt;/em&gt;.
    &lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.db&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;stdfields.models&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Enum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EnumValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EnumCharField&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CardinalDirection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Enum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;NORTH&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EnumValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;N&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;North&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;NORTHEAST&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EnumValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;NE&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;Northeast&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;EAST&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EnumValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;E&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;East&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;SOUTHEAST&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EnumValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;SE&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;Southeast&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;SOUTH&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EnumValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;S&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;South&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;SOUTHWEST&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EnumValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;SW&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;Southwest&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;WEST&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EnumValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;W&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;West&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;NORTHWEST&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EnumValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;NW&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;Northwest&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Wind&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;direction&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EnumCharField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;enum&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CardinalDirection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
                            &lt;span class=&quot;n&quot;&gt;max_length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CardinalDirection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;force&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IntegerField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

    &lt;p&gt;
        We just added northeast, southeast, southwest and northwest to the 
        possible values. Did you notice that this also changes the maximum 
        length for the &lt;code&gt;direction&lt;/code&gt; field of &lt;code&gt;Wind&lt;/code&gt;?
    &lt;/p&gt;
    &lt;p&gt;
        Well, it doesn&#39;t matter: we&#39;re using the &lt;code&gt;max_length&lt;/code&gt; method
        provided by &lt;code&gt;Enumeration&lt;/code&gt; which will automatically determine
        the maximum possible length of the values &amp;mdash; in this case 2. Just
        don&#39;t forget to create and run a schema migration with&amp;nbsp;South.
    &lt;/p&gt;
    &lt;p&gt;
        But &lt;code&gt;Enum&lt;/code&gt; might not work entirely as expected: when it&#39;s
        constructed, all contained &lt;code&gt;EnumValue&lt;/code&gt; fields will be turned
        into regular&amp;nbsp;fields:
    &lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CardinalDirection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NORTH&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;N&amp;#39;&lt;/span&gt;
&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CardinalDirection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NORTH_display&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;North&amp;#39;&lt;/span&gt;
&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CardinalDirection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;N&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;North&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;NE&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;Northeast&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;E&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;East&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;SE&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;Southeast&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; 
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;S&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;South&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;SW&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;Southwest&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;W&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;West&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;NW&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;Northwest&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CardinalDirection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CardinalDirection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;as_display&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CardinalDirection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NORTH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;&amp;#39;North&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

    &lt;p&gt;
        That&#39;s the gist of django-stdfields. It will save me a lot of time
        and I hope it does the same for you. Get it from 
        &lt;a href=&quot;http://pypi.python.org/pypi/django-stdfields/&quot;&gt;Pypi&lt;/a&gt;
        or &lt;a href=&quot;https://bitbucket.org/roam/django-stdfields/&quot;&gt;Bitbucket&lt;/a&gt;.
    &lt;/p&gt;

				</content></entry><entry><title>Converting a WordPress blog into a static site</title><author><name>Kevin Wetzels</name></author><link href="http://roam.be/notebook/2011/converting-wp-blog-to-static-site.html"/><updated>2011-10-03T13:13:34Z</updated><published>2011-10-03T13:13:34Z</published><id>http://roam.be/notebook/2011/converting-wp-blog-to-static-site.html</id><content type="html">
					
	&lt;div class=&quot;intro&quot;&gt;
		&lt;p&gt;
			&lt;!-- Hyde::Excerpt::Begin --&gt;
			My personal blog at &lt;a href=&quot;http://el73.be&quot;&gt;el73&lt;/a&gt; hasn&#39;t seen
			an update in years. Constantly upgrading WordPress because of a newly
			discovered security hole on a website I no longer publish to feels
			a lot like wasting time.
			&lt;!-- Hyde::Excerpt::End --&gt;
		&lt;/p&gt;
	&lt;/div&gt;
	&lt;p&gt;
	    That&#39;s why I decided to finally remove the WordPress parts from the 
	    equation and turn the blog into a static, archived site. Two tools
	    made this conversion easier than I could have imagined from the&amp;nbsp;start.
	&lt;/p&gt;
	&lt;h2&gt;Wget&lt;/h2&gt;
	&lt;p&gt;
	    The first step was to archive the entire published site. With a little
	    help from &lt;code&gt;wget&lt;/code&gt; I got all of around 500 pages downloaded
	    in a little less than an hour, thanks to &lt;a href=&quot;http://fosswire.com/post/2008/04/create-a-mirror-of-a-website-with-wget/&quot;&gt;Peter Upfold&lt;/a&gt; 
	    and this command: &lt;code&gt;$ wget -mk -w 20 http://el73.be/&lt;/code&gt;
	&lt;/p&gt;
	&lt;h2&gt;Cleaning up the&amp;nbsp;HTML&lt;/h2&gt;
    &lt;p&gt;
        So now I&#39;ve got a local mirror of the site, but I need to change some
        things around. Since I&#39;m not planning on keeping WordPress around, 
        the form to add a comment will have to be removed. Plus there&#39;s a link
        to search the website&#39;s contents in the navigation. Since that&#39;s also
        powered by WordPress, it&#39;ll have to be removed as&amp;nbsp;well.
    &lt;/p&gt;
    &lt;p&gt;
        My first attempt to clean up the HTML consisted of processing all the HTML files and removing
        those two parts using regular expressions. Now, I&#39;m no command line guru
        chaining 5 separate commands into a single perfectly working 
        combination of *nix glory. And as it turns out, OSX doesn&#39;t support the
        full range of arguments offered by &lt;code&gt;grep&lt;/code&gt; on other systems
        such as Linux anyway. Sure, I could have delved in and wasted a lot of time on 
        getting this to work, but it would be just that: wasting time. I&#39;m not 
        planning on doing this again anytime soon, so whatever works best and 
        &lt;em&gt;right now&lt;/em&gt; is going to get my&amp;nbsp;vote.
    &lt;/p&gt;
    &lt;p&gt;
        As it turns out, &lt;a href=&quot;http://phantomjs.org&quot;&gt;PhantomJS&lt;/a&gt; is what
        worked best for me. PhantomJS allowed me to use a simple script that
        would walk the entire mirrored site and collect the HTML files. After
        that, it was a matter of loading each HTML file, removing the elements
        I wanted removed using plain DOM operations and saving the content
        back to&amp;nbsp;file.
    &lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;cleanUpHtml&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Open the file at the given location&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Cleaning up HTML in &amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;file://&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Opening file at &amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;page&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;WebPage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;status&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;success&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Unable to load &amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;innerHtml&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;evaluate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;// Remove the comment form&lt;/span&gt;
                &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;el&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;commentform&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;nx&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;parentNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;removeChild&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;// Remove the search link&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;el&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;nav&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;el&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tagName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;UL&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;lis&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getElementsByTagName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;LI&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;lis&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;lis&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                        &lt;span class=&quot;nx&quot;&gt;el&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;removeChild&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;lis&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
                    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;// And return the inner HTML of the root&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;documentElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;innerHTML&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// Wrap the inner HTML&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;fs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;&amp;lt;!DOCTYPE HTML&amp;gt;&amp;lt;html lang=&amp;quot;nl&amp;quot;&amp;gt;&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;innerHtml&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;&amp;lt;/html&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;w&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39; processed&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

    &lt;h2&gt;Upload... and&amp;nbsp;profit!&lt;/h2&gt;
    &lt;p&gt;
        So that&#39;s how I could turn an entire website backed by WordPress into
        a site consisting of nothing but static assets in about 2 hours of work,
        not counting the time needed to download and process the pages. Upgrading
        to the next two patched versions of WordPress would probably cost me
        the same or&amp;nbsp;more.
    &lt;/p&gt;

				</content></entry><entry><title>Introducing Extractor</title><author><name>Kevin Wetzels</name></author><link href="http://roam.be/notebook/2011/introducing-extractor.html"/><updated>2011-07-30T19:58:30Z</updated><published>2011-07-30T19:58:30Z</published><id>http://roam.be/notebook/2011/introducing-extractor.html</id><content type="html">
					
	&lt;div class=&quot;intro&quot;&gt;
		&lt;p&gt;
			&lt;!-- Hyde::Excerpt::Begin --&gt;
			Sometimes you&#39;re faced with an almost impossible decision, trying
			to make sure &lt;strong&gt;all&lt;/strong&gt; your users are happy with what 
			they&#39;re working with.
			&lt;!-- Hyde::Excerpt::End --&gt;
		&lt;/p&gt;
	&lt;/div&gt;
	&lt;p&gt;
	    One such decision is where to place the comments and remarks on 
	    something crucial. Say, a chapter in a book review system. Place them
	    on the bottom and you have to scroll back and forth between the comments
	    and the text. Place them at the side and you&#39;re going to have to create
	    a layout that makes this possible without hindering people working at 
	    lower screen resolutions. Thanks to 
	    &lt;a href=&quot;/lab/extractor&quot;&gt;Extractor&lt;/a&gt; there is another 
	    option: show the comments at the bottom, but let the user pull them out
	    into a dialog, backed by &lt;a href=&quot;http://jqueryui.com/&quot;&gt;jQuery UI&lt;/a&gt;.
	    That way they can move the dialog around the page and resize it to their&amp;nbsp;liking.
	&lt;/p&gt;
	&lt;h2&gt;But...&lt;/h2&gt;
	&lt;p&gt;
	    Once you have loaded content into a dialog, you can&#39;t really get it
	    back out. jQuery UI will move it to the bottom of your &lt;code&gt;body&lt;/code&gt;
	    element and often that&#39;s not what you&#39;d like to see&amp;nbsp;happening.
	&lt;/p&gt;
	&lt;p&gt;
	    And that&#39;s where Extractor steps in: instead of simply letting jQuery&#39;s
	    dialog do it&#39;s thing, it inserts a placeholder for your content and,
	    when the dialog is closed, places the content right back where it&amp;nbsp;belongs.
	&lt;/p&gt;
    &lt;p&gt;
        &lt;a href=&quot;/lab/extractor&quot;&gt;Have a look at the demo and grab a copy of&amp;nbsp;Extractor.&lt;/a&gt;
    &lt;/p&gt;
    &lt;a href=&quot;http://widgetthemes.be/&quot; id=&quot;widgetthemes&quot;&gt;
    &lt;img src=&quot;/media/img/widgetthemes-logo.png&quot; width=&quot;231&quot; height=&quot;36&quot; alt=&quot;WidgetThemes&quot;&gt;
    &lt;p&gt;
        Like jQuery UI? You&#39;ll probably &lt;em&gt;love&lt;/em&gt;
        &lt;strong&gt;WidgetThemes&lt;/strong&gt;, our new project that delivers 
        &lt;strong&gt;high quality jQuery UI themes&lt;/strong&gt;.
    &lt;/p&gt;
&lt;/a&gt;

				</content></entry><entry><title>Writing tests is not a waste of time</title><author><name>Kevin Wetzels</name></author><link href="http://roam.be/notebook/2011/writing-tests-is-not-a-waste-of-time.html"/><updated>2011-03-26T08:23:43Z</updated><published>2011-03-26T08:23:43Z</published><id>http://roam.be/notebook/2011/writing-tests-is-not-a-waste-of-time.html</id><content type="html">
					
	&lt;div class=&quot;intro&quot;&gt;
		&lt;p&gt;
			&lt;!-- Hyde::Excerpt::Begin --&gt;
			When providing estimates on a project I always include the time
			needed to write up the tests because they are often necessary to
			provide a quick turnaround on changing requirements and inevitable bugfixes.
			&lt;!-- Hyde::Excerpt::End --&gt;
		&lt;/p&gt;
	&lt;/div&gt;
	&lt;p&gt;
	    Some managers and customers would prefer software to work as intended 
	    from the get-go &lt;em&gt;without&lt;/em&gt; tests, but, unless you&#39;re developing the
	    simplest of applications, tests are an absolute necessity. Simply telling
	    your customer that &lt;q&gt;&quot;tests are necessary&quot;&lt;/q&gt; probably won&#39;t do, so here&#39;s a
	    list of reasons why they are important that I often&amp;nbsp;employ.
	&lt;/p&gt;
	&lt;h2&gt;Requirements&amp;nbsp;change&lt;/h2&gt;
	&lt;p&gt;
	    Sure, the format of the files you need to process each night isn&#39;t going
	    to change. Until the release is two days away and it turns out
	    the format has changed from CSV to XML. With adequate tests in place, 
	    you can replace the file parser and know almost exactly where you stand 
	    without having to wait for the application to be tested by a&amp;nbsp;human.
	&lt;/p&gt;
	&lt;p&gt;
	    Of course, this &lt;em&gt;does&lt;/em&gt; mean you&#39;ll have to change the tests for 
	    the file parser, but isn&#39;t that the easiest way to find out that your 
	    parser actually&amp;nbsp;works?
	&lt;/p&gt;
	&lt;p&gt;
	    During a project at the Belgian Post Group (now &lt;em&gt;bpost&lt;/em&gt;), we used
	    each new version, each change in requirements, of a pretty complex application to add more and more 
	    tests. The number of issues to pop up during user acceptance testing 
	    went down. &lt;strong&gt;Way down&lt;/strong&gt;. So far down in fact that we had to find other 
	    things to do in the days leading up to the release, while a few months 
	    earlier we&#39;d still be squashing bugs left and&amp;nbsp;right.
	&lt;/p&gt;
	&lt;p&gt;
	    Plus: the testing framework we developed during that project served 
	    as a baseline for &lt;a href=&quot;http://unitils.org&quot;&gt;Unitils&lt;/a&gt;, proving that
	    not all testing code you write needs to be redone in your next&amp;nbsp;project.
	&lt;/p&gt;
	&lt;h2&gt;Code gets&amp;nbsp;ugly&lt;/h2&gt;
	&lt;p&gt;
	    No matter how hard you try to think about the code you&#39;re going to write,
	    at some point you&#39;ll start to notice duplicate code that can be merged into a 
	    single function and weird constructs that can be simplified from 200 lines
	    to 10 lines. Tests have your back and make sure you &lt;strong&gt;can&lt;/strong&gt;
	    merge and simplify without breaking the&amp;nbsp;app.
	&lt;/p&gt;
	&lt;p&gt;
	    Imagine a piece of logic &amp;mdash; let&#39;s say some kind of calculation 
	    based on government regulation &amp;mdash; that&#39;s already been tested by the
	    same person five different times. They &lt;strong&gt;will&lt;/strong&gt; get sick of it and 
	    they will start to skip the testing. Why? Because it all worked up till
	    now, so why would &lt;em&gt;now&lt;/em&gt; be any different? And that&#39;s when you
	    come along. You find out the code you&#39;ve written three weeks ago in part
	    of the calculation is actually the same as the code you&#39;ve just finished
	    writing. You merge both parts into a single function, but forget about 
	    that single tiny special case you needed to take into&amp;nbsp;account.
	&lt;/p&gt;
	&lt;p&gt;
	    &lt;strong&gt;Boom!&lt;/strong&gt; Your new report works perfectly, but your 
	    calculation is broken. Chances are nobody will find out until it&#39;s too&amp;nbsp;late.
	&lt;/p&gt;
	&lt;img style=&quot;margin-right:-340px;float:right&quot; src=&quot;/media/img/notebook/tests.png&quot; width=&quot;585&quot; height=&quot;392&quot; alt=&quot;Strive for tests, strive for working tests, strive for successful tests&quot;&gt;
	&lt;p&gt;
	    Recently, I found out code I had been working on for days failed in
	    some scenarios I hadn&#39;t even considered up till then. By the time the first
	    fixes were applied, the code had grown out of control. And then 
	    &lt;em&gt;another&lt;/em&gt; bug popped&amp;nbsp;up.
	&lt;/p&gt;
	&lt;p&gt;
	    I decided to add the newly discovered scenarios to the existing tests and 
	    rip out the entire part. I rewrote it to spec (i.e. the tests) in under 
	    4&amp;nbsp;hours.
	&lt;/p&gt;
	&lt;h2&gt;Tests are more valuable than&amp;nbsp;comments&lt;/h2&gt;
	&lt;p&gt;
	    When you&#39;re the kind of developer who reads the comments detailing what a 
	    method does and how it will respond to certain input, you&#39;ve probably
	    seen your fair part of &lt;em&gt;paradocs&lt;/em&gt;: the documentation accompanying
	    the signature says &quot;A&quot; while your experience seems to indicate it&#39;s actually&amp;nbsp;&quot;X&quot;.
	&lt;/p&gt;
	&lt;p&gt;
	    Given clear-cut test cases you&#39;ll soon find out whether the original
	    developer (maybe it was&amp;nbsp;you):
	&lt;/p&gt;
	&lt;ul&gt;
	    &lt;li&gt;changed the code and forgot to update the docs;&amp;nbsp;or&lt;/li&gt;
	    &lt;li&gt;wrote buggy code and wrote the docs without verifying the code responded as&amp;nbsp;expected&lt;/li&gt;
	&lt;/ul&gt;
	&lt;p&gt;
	    Tests clarify how you expect your code to be&amp;nbsp;used.
	&lt;/p&gt;
	&lt;h2&gt;Tests can speed up&amp;nbsp;development&lt;/h2&gt;
	&lt;p&gt;
	    Don&#39;t believe me? In a current project we&#39;re using 
	    &lt;a href=&quot;http://jbpm.org&quot;&gt;JBPM&lt;/a&gt; to embed workflows in a webapp.
	    Using JUnit I can make sure that the implemented workflow works as 
	    expected. This means an email is sent out when expected to the people
	    I expected. This means the &lt;code&gt;Send out order&lt;/code&gt; step will always
	    occur &lt;em&gt;after&lt;/em&gt; the &lt;code&gt;Verify payment&lt;/code&gt; step. This means
	    I&#39;ll always have a quick comeback to an issue logged by a tester or
	    customer titled &lt;em&gt;&quot;The workflow doesn&#39;t work as expected&quot;&lt;/em&gt;.
	&lt;/p&gt;
	&lt;p&gt;
	    Besides, would &lt;em&gt;you&lt;/em&gt; rather compile the entire application, start Tomcat, wait
	    for the application to load and then start clicking away or would you
	    prefer to hit the &quot;Run test&quot; button in your IDE and have the results
	    displayed to you within&amp;nbsp;seconds?
    &lt;/p&gt;
    &lt;p&gt;
        Here&#39;s another benefit: the next time your customer asks you whether
        it would be possible to add an extra step to the workflow and how much time
        and money it will cost, you&#39;ll open up your test cases and have a look.
        Maybe you&#39;ll add the step right away, to see how your tests will react.
        Imagine, just imagine, responding to the customer&#39;s request with a simple &quot;Done!&quot; instead
        of a long winding response detailing why you&#39;ll need 10 days to include
        a &lt;code&gt;Review order&lt;/code&gt; step.
    &lt;/p&gt;
    &lt;h2&gt;Tests are no magic&amp;nbsp;bullet&lt;/h2&gt;
    &lt;p&gt;
        Unfortunately, someone still has to make sure your web application works
        in Internet Explorer 7 and the &quot;Log in&quot; button is visible on an iPad. But
        that needs to happen less and less, while you add more and more&amp;nbsp;tests.
    &lt;/p&gt;
    &lt;p&gt;
        Just make sure the things you&#39;re testing are worth it. When 2 + 2 no
        longer equals 4, you&#39;ll have bigger fish to&amp;nbsp;fry.
    &lt;/p&gt;

				</content></entry><entry><title>jQuery dialog: keep your hands of my content!</title><author><name>Kevin Wetzels</name></author><link href="http://roam.be/notebook/2012/jquery-dialog-keep-your-hands-of-my-content.html"/><updated>2012-04-07T11:10:10Z</updated><published>2012-04-07T11:10:10Z</published><id>http://roam.be/notebook/2012/jquery-dialog-keep-your-hands-of-my-content.html</id><content type="html">
					
    &lt;div class=&quot;intro&quot;&gt;
        &lt;p&gt;
            &lt;!-- Hyde::Excerpt::Begin --&gt;
                People who are new to jQuery UI often are surprised when
                they open a dialog using a piece of HTML that&#39;s on the page. 
                Where&#39;s your HTML? What&#39;s happening? How do you prevent it from happening?
            &lt;!-- Hyde::Excerpt::End --&gt;
        &lt;/p&gt;
    &lt;/div&gt;
    &lt;h2&gt;Poof!&amp;nbsp;Gone&lt;/h2&gt;
    &lt;p&gt;
        When you generate a dialog from part of your webpage, you&#39;ll
        notice that when you open the dialog that text &lt;em&gt;disappears&lt;/em&gt; from the
        page and shows up in your dialog. Once you close that 
        dialog, however, your text is&amp;nbsp;gone.
    &lt;/p&gt;
    &lt;p&gt;
        jQuery UI actually takes the content you want to create a dialog from,
        wraps it in all kinds of divs to make sure it renders correctly and then
        places it at the bottom of your page. Hidden. Until you either open
        the dialog or the dialog&amp;nbsp;auto-opens.
    &lt;/p&gt;
    &lt;p&gt;
        So how do you prevent that from happening? How do you keep the content
        on your page without jQuery UI moving it&amp;nbsp;around?
    &lt;/p&gt;
    &lt;h2&gt;Option 1: use jQuery&amp;nbsp;Extractor&lt;/h2&gt;
    &lt;p&gt;
        If you actually &lt;strong&gt;want&lt;/strong&gt; to remove the content from the page, 
        but you want jQuery UI to &lt;strong&gt;put it back when the dialog is closed&lt;/strong&gt;,
        use &lt;a href=&quot;/lab/extractor/&quot; title=&quot;jQuery Extractor: pulls content into a dialog and puts it back once you&#39;re done&quot;&gt;jQuery Extractor&lt;/a&gt;.
    &lt;/p&gt;
    &lt;p&gt;
        This scenario is exactly &lt;a href=&quot;/notebook/2011/introducing-extractor.html&quot; title=&quot;Back in July 2011 I open-sourced jQuery Extractor and explained why I needed it&quot;&gt;why I created jQuery Extractor in the first
        place&lt;/a&gt;.
    &lt;/p&gt;
    &lt;h2&gt;Option 2: copy before you&amp;nbsp;pop&lt;/h2&gt;
    &lt;p&gt;
        So you&#39;ve got this HTML you want to load into a&amp;nbsp;dialog.
    &lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;mydialog&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;title=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;My dialog!&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    Oh, hi!
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

    &lt;p&gt;
        The easy way that &lt;em&gt;does not&lt;/em&gt; work if you want to get your content&amp;nbsp;back:
    &lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;#mydialog&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dialog&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

    &lt;p&gt;
        So why don&#39;t we just make a copy of the HTML and load that? Now, be 
        careful! Like we said before: the HTML is actually still part of the
        page. So when you&#39;re using an &lt;code&gt;id&lt;/code&gt; attribute to identify the part you
        want to load, you&#39;ll get multiple elements with the same &lt;em&gt;unique&lt;/em&gt; identifier. That&#39;s no&amp;nbsp;good.
    &lt;/p&gt;
    &lt;p&gt;
        We&#39;ve got to think a bit ahead. Let&#39;s adapt the&amp;nbsp;HTML.
    &lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;mydialog-wrapper&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;title=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;My dialog!&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        Oh, hi!
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

    &lt;p&gt;
        We introduced a wrapper we can use to identify the HTML fragment
        we want to display in a jQuery UI&amp;nbsp;dialog.
    &lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dialogHtml&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;#mydialog-wrapper&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dialogHtml&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dialog&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

    &lt;p&gt;
        And that&#39;s the final part of the puzzle. We take the contents of our
        wrapper and wrap that HTML in a jQuery object which comes down to making
        a copy of that HTML. Then we call jQuery UI&#39;s &lt;code&gt;dialog&lt;/code&gt; method 
        on that instead of the&amp;nbsp;original.
    &lt;/p&gt;
    &lt;a href=&quot;http://widgetthemes.be/&quot; id=&quot;widgetthemes&quot;&gt;
    &lt;img src=&quot;/media/img/widgetthemes-logo.png&quot; width=&quot;231&quot; height=&quot;36&quot; alt=&quot;WidgetThemes&quot;&gt;
    &lt;p&gt;
        Like jQuery UI? You&#39;ll probably &lt;em&gt;love&lt;/em&gt;
        &lt;strong&gt;WidgetThemes&lt;/strong&gt;, our new project that delivers 
        &lt;strong&gt;high quality jQuery UI themes&lt;/strong&gt;.
    &lt;/p&gt;
&lt;/a&gt;

				</content></entry></feed>
