<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>unitstep.net</title>
	
	<link>http://unitstep.net</link>
	<description>the home of peter chng</description>
	<lastBuildDate>Mon, 19 Mar 2012 01:49:33 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/unitstep" /><feedburner:info uri="unitstep" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>Java’s Pattern class and regular expressions</title>
		<link>http://feedproxy.google.com/~r/unitstep/~3/ta9aursG3oM/</link>
		<comments>http://unitstep.net/blog/2012/03/18/javas-pattern-class-and-regular-expressions/#comments</comments>
		<pubDate>Mon, 19 Mar 2012 01:47:20 +0000</pubDate>
		<dc:creator>Peter Chng</dc:creator>
				<category><![CDATA[java]]></category>
		<category><![CDATA[regex]]></category>
		<category><![CDATA[tutorials]]></category>
		<category><![CDATA[java regex tutorial]]></category>

		<guid isPermaLink="false">http://unitstep.net/?p=1366</guid>
		<description><![CDATA[One of the easiest things to get tripped up on is the syntax for creating regular expressions (regex) in Java using the Pattern class. The tl;dr version of how to do things is that you must use double-backslashes in the regular expression Strings you use to create a Pattern object; so something like \b would [...]]]></description>
			<content:encoded><![CDATA[<p>One of the easiest things to get tripped up on is the syntax for creating regular expressions (regex) in Java using the <a href="http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html">Pattern</a> class. The <em>tl;dr</em> version of how to do things is that <strong>you must use double-backslashes in the regular expression Strings you use to create a Pattern object</strong>; so something like <code>\b</code> would have to be written as <code>"\\b"</code>.  Read on for a more thorough explanation.</p>
<h2>Double trouble</h2>
<p>The key point to understanding the tricky syntax is to realize that when you&#8217;re creating a String literal in Java, backslashes are used to form escape sequences as well. Most people are familiar with this concept, when, for example, constructing a String that spans multiple lines:</p>
<pre><code>final String multiline = "A String...\nOn two lines";</code></pre>
<p>When calling <code>Pattern.compile</code>, you pass in a String literal that is the regular expression. However, regular expressions also use the backslash character to begin escape sequences. So, to ensure that the regular expression engine in Pattern gets the correct syntax, you must replace every backslash in your regular expression with two backslashes. This is to prevent Java from interpreting the single backslash as just a String escape sequence.</p>
<p>Or, put another way, if you wanted a String with the contents <code>"\n"</code>, that is a String with a backslash followed by the letter &#8216;n&#8217;, you&#8217;d have to define it as:</p>
<pre><code>final String newLineEscapeSequence = "\\n";</code></pre>
<p>This is the gist of it; we need to pass in the preserved backslashes into the Pattern regular expression engine, so you have to create a literal backslash by using a double-backslash in your String literal. This information is in the <a href="http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html">Pattern Javadoc</a>, but it&#8217;s sort of buried beneath loads of regular expression syntax. </p>
<p>Keep this in mind when constructing your regular expressions outside of Java in a tool like <a href="http://gskinner.com/RegExr/">RegExr</a>.  These principles also apply when using other classes/methods that use <code>Pattern</code>, such as <code><a href="http://docs.oracle.com/javase/6/docs/api/java/lang/String.html#split%28java.lang.String%29">String.split()</a></code> or <code><a href="http://docs.oracle.com/javase/6/docs/api/java/util/Scanner.html#useDelimiter%28java.util.regex.Pattern%29">Scanner.useDelimiter()</a></code></p>
<h2>An example</h2>
<p>Here&#8217;s a simple example where we try to find the word &#8220;The&#8221; at the beginning of a String, delimited by a word boundary matcher.</p>
<pre><code>public class PatternExample {
  private static final Logger LOGGER =
      Logger.getLogger(PatternExample.class);
  private static final String TEST_STRING =
      "The quick brown fox jumps over the lazy dog";

  public static void main(final String[] args) {
    System.out.println(TEST_STRING);

    final Pattern wordBoundaryWrong = Pattern.compile("^The\b.*");
    Matcher matcher = wordBoundaryWrong.matcher(TEST_STRING);
    LOGGER.debug(matcher.matches()); // false.

    final Pattern wordBoundaryCorrect = Pattern.compile("^The\\b.*");
    matcher = wordBoundaryCorrect.matcher(TEST_STRING);
    LOGGER.debug(matcher.matches()); // true.
  }
}</code></pre>
<p>The key point here is that the word boundary matcher (<code>\b</code>) must be passed in as a String literal of <code>"\\b"</code> so that the backslash is properly interpreted. In the incorrect Pattern, <code>"\b"</code> maps to a <a href="http://docstore.mik.ua/orelly/java-ent/jenut/ch10_05.htm">backspace character literal</a>.</p>
<p>I think the reason this concept is somewhat tricky is that you have to deal with two levels of escaping &#8211; the Java String literal syntax and the Regular Expression syntax.</p>
<hr/>Copyright &copy; 2012 <strong><a href="http://unitstep.net">unitstep.net</a></strong>. This Feed is for personal non-commercial use only. If you are not reading this material in your news aggregator, the site you are looking at is guilty of copyright infringement. Please contact <strong><a href="mailto:webmaster@unitstep.net">webmaster@unitstep.net</a></strong> for more information.<br/><span style="float: right;font-size: 7pt"><a href="http://blog.taragana.com/index.php/archive/wordpress-plugins-provided-by-taraganacom/">Plugin</a> by <a href="http://www.taragana.com/">Taragana</a></span><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/unitstep?a=ta9aursG3oM:wkkSNgSf91E:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/unitstep?i=ta9aursG3oM:wkkSNgSf91E:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=ta9aursG3oM:wkkSNgSf91E:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/unitstep?i=ta9aursG3oM:wkkSNgSf91E:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=ta9aursG3oM:wkkSNgSf91E:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/unitstep?i=ta9aursG3oM:wkkSNgSf91E:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=ta9aursG3oM:wkkSNgSf91E:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/unitstep?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=ta9aursG3oM:wkkSNgSf91E:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/unitstep?d=yIl2AUoC8zA" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/unitstep/~4/ta9aursG3oM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://unitstep.net/blog/2012/03/18/javas-pattern-class-and-regular-expressions/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://unitstep.net/blog/2012/03/18/javas-pattern-class-and-regular-expressions/</feedburner:origLink></item>
		<item>
		<title>The Game of Life and emergence</title>
		<link>http://feedproxy.google.com/~r/unitstep/~3/zu0mcE6FRBc/</link>
		<comments>http://unitstep.net/blog/2012/02/12/the-game-of-life-and-emergence/#comments</comments>
		<pubDate>Mon, 13 Feb 2012 01:37:54 +0000</pubDate>
		<dc:creator>Peter Chng</dc:creator>
				<category><![CDATA[algorithms]]></category>
		<category><![CDATA[asides]]></category>
		<category><![CDATA[Life]]></category>
		<category><![CDATA[emergence]]></category>

		<guid isPermaLink="false">http://unitstep.net/?p=1326</guid>
		<description><![CDATA[I have had a side interest in emergent behaviour ever since reading about various forms in nature, so when a co-worker sent me a link to Conway&#8217;s Game of Life, I was immediately intrigued. Long story short, I just had to implement it (albeit a simple version) in JavaScript. The result is available on my [...]]]></description>
			<content:encoded><![CDATA[<p>I have had a side interest in emergent behaviour ever since reading about various forms in nature, so when a co-worker sent me a link to <a href="http://en.wikipedia.org/wiki/Conway%27s_Game_of_Life">Conway&#8217;s Game of Life</a>, I was immediately intrigued.</p>
<p>Long story short, I just had to implement it (albeit a simple version) in JavaScript. The <a href="http://unitstep.net/projects/game-of-life/">result is available</a> on my website and I suggest you give it a try; a good pattern to start out with is the <a href="http://en.wikipedia.org/wiki/File:Game_of_life_fpento.svg">F-pentomino</a>.</p>
<p>The reason I find emergence so interesting is that it provides a possible framework or explanation for the complexity and order seen in our universe, based on a fairly simple or rudimentary set of rules.</p>
<h2>One to rule them all</h2>
<p>The interactions seen in <em>Conway&#8217;s Game of Life</em> can be fairly complex and are not straightforward to predict. However, they all result from a simple set of rules:</p>
<ul>
<li>Each square is labeled as a cell, and has eight neighbours.</li>
<li>A cell can either be &#8220;dead&#8221; or &#8220;alive&#8221;.</li>
<li>A dead cell turns alive on the next turn if it has exactly three alive neighbours.</li>
<li>A live cell continues to live on the next turn if it has 2 or 3 alive neighbours.</li>
</ul>
<p>Thus, during each iteration, the state of a cell (alive or dead) is determined from the state of its neighbours on the previous turn.</p>
<h2>Complexity from simplicity</h2>
<p>Despite this limited ruleset, complex behaviour can be seen in the interaction between cells. In fact, quite a lot of study has been put into understanding the interactions and categorizing the various &#8220;structures&#8221; that have emerged in game. </p>
<p>Simulating the game on a large scale can take a lot of CPU power, so some interesting dynamic programming techniques have been utilized to increase the iteration speed. One of them is <a href="http://en.wikipedia.org/wiki/Hashlife">Hashlife</a>, which exploits the repeatability and determinism in the game.</p>
<p>For example, if a pattern shows up an in an early stage of the simulation, it&#8217;s &#8220;evolution&#8221; can be tracked and stored so that if the same pattern ever shows up again, it&#8217;s long(er) term fate will already be known, since it was already computed earlier. This prevents unnecessary iterations in the simulation. This sort of technique is called <em>memoization</em>.</p>
<h2>In Real Life</h2>
<p>Obviously, our universe is probably more complex than the <em>Game of Life</em>. (It would likely have to be, since the simulation exists within our universe) But it&#8217;s also likely that all the complex interactions and structures observed in our universe boil down to some set of rudimentary rules.  The point of science, in many respects, is connecting the dots that allow us to understand how these higher-level properties emerged from lower-level interactions. I&#8217;m not saying that it will provide all the answers or explain things like self-awareness, but to me, that sort of emergence is the real beauty of our universe. </p>
<hr/>Copyright &copy; 2012 <strong><a href="http://unitstep.net">unitstep.net</a></strong>. This Feed is for personal non-commercial use only. If you are not reading this material in your news aggregator, the site you are looking at is guilty of copyright infringement. Please contact <strong><a href="mailto:webmaster@unitstep.net">webmaster@unitstep.net</a></strong> for more information.<br/><span style="float: right;font-size: 7pt"><a href="http://blog.taragana.com/index.php/archive/wordpress-plugins-provided-by-taraganacom/">Plugin</a> by <a href="http://www.taragana.com/">Taragana</a></span><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/unitstep?a=zu0mcE6FRBc:Y-ysxpcLFSI:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/unitstep?i=zu0mcE6FRBc:Y-ysxpcLFSI:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=zu0mcE6FRBc:Y-ysxpcLFSI:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/unitstep?i=zu0mcE6FRBc:Y-ysxpcLFSI:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=zu0mcE6FRBc:Y-ysxpcLFSI:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/unitstep?i=zu0mcE6FRBc:Y-ysxpcLFSI:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=zu0mcE6FRBc:Y-ysxpcLFSI:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/unitstep?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=zu0mcE6FRBc:Y-ysxpcLFSI:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/unitstep?d=yIl2AUoC8zA" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/unitstep/~4/zu0mcE6FRBc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://unitstep.net/blog/2012/02/12/the-game-of-life-and-emergence/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://unitstep.net/blog/2012/02/12/the-game-of-life-and-emergence/</feedburner:origLink></item>
		<item>
		<title>Shuffle sort and other fallacies of randomization</title>
		<link>http://feedproxy.google.com/~r/unitstep/~3/teJdn-7Xcgg/</link>
		<comments>http://unitstep.net/blog/2012/02/05/shuffle-sort-and-other-fallacies-of-randomization/#comments</comments>
		<pubDate>Mon, 06 Feb 2012 01:23:17 +0000</pubDate>
		<dc:creator>Peter Chng</dc:creator>
				<category><![CDATA[algorithms]]></category>
		<category><![CDATA[randomization]]></category>
		<category><![CDATA[randomization microsoft browser eu probability]]></category>

		<guid isPermaLink="false">http://unitstep.net/?p=1098</guid>
		<description><![CDATA[Quick, how do you write code that shuffles a collection of objects? In the real world, it&#8217;s fairly easy to see how a deck of cards is shuffled &#8211; but how would you do that in code? Obviously, you would have to use some sort of random number generator, but beyond that it&#8217;s not straightforward. [...]]]></description>
			<content:encoded><![CDATA[<p>Quick, how do you write code that shuffles a collection of objects? In the real world, it&#8217;s fairly easy to see how a deck of cards is shuffled &#8211; but how would you do that in code? Obviously, you would have to use some sort of random number generator, but beyond that it&#8217;s not straightforward. Furthermore, how do you ensure that the shuffling is <em>fair</em>; that is, all permutations appear with equal probability?</p>
<p>The astute among you will know that one way is by implementing the <a href="http://bost.ocks.org/mike/shuffle/">Fisher-Yates shuffle algorithm</a>. But, let&#8217;s investigate what happens when other, seemingly adequate solutions, are used instead.</p>
<h2>Shuffler&#8217;s dilemma</h2>
<p>One example that highlights the implications of using <em>seemingly</em> random and unbiased &#8220;shuffling&#8221; involves the <a href="http://arstechnica.com/microsoft/news/2010/03/coding-error-leads-to-uneven-eu-browser-ballot-distribution.ars">Windows EU Browser Ballot</a>.</p>
<p>The purpose of the Browser Ballot was so that <a href="http://arstechnica.com/microsoft/news/2010/02/microsofts-eu-browser-ballot-approved-arrives-march-1.ars">Microsoft could comply with an EU directive</a> that ordered them to provide users with a clear choice of which browser to use with Windows. The ballot was supposed to have been carefully designed; the first section contained the five most common browsers (Chrome, Firefox, Internet Explorer, Opera and Safari) with the second section containing seven lesser-used browsers.</p>
<p>Since it is generally considered an advantage to be placed first in a ballot (because users who don&#8217;t care one way or another might just pick the first option), the EU directed Microsoft to randomize the order in which the browsers appeared on the ballot in each of the sections. Thus, when users visited the ballot page, they were supposed to get a random ordering of the top five browsers followed by a random ordered of the lesser seven.</p>
<h2>Looking into the cards</h2>
<p>The team in charge of the ballot design came up with a solution to use a sorting function with a randomized comparator. In this way, they hoped to apply a randomized sort to the list of browsers, producing a random ordering that met the rules of the EU.  While this did produce a random ordering, (and thus technically was in compliance with the EU directive), it did not produce unbiased results, as the ordering of some browsers came up more often than others. This lead to allegations that Microsoft was trying yet again to stifle its competition to unscrupulous practices.</p>
<p>However, this probably wasn&#8217;t the case, and was likely an instance of a seemingly adequate solution being used without proper testing/analysis.</p>
<p>To understand the problem, we first have to understand sorting algorithms, specifically those that use comparisons as their basis. (i.e. <em>comparison sorts</em>) An example of a comparison sort is <em><a href="http://www.personal.kent.edu/~rmuhamma/Algorithms/MyAlgorithms/Sorting/insertionSort.htm">Insertion sort</a></em>. Through each step of the sorting process, the sorted portion of the list increases by one as we take the next element from the unsorted portion and position it properly within the sorted portion. This is done by <em>comparing</em> the element to be inserted with each element in the sorted portion until we find the correct position.</p>
<p>A <em>comparator</em> is simply a function that compares two objects, and tells us which one is greater than the other, or whether they are equal. In Java, the general structure of a <a href="http://docs.oracle.com/javase/6/docs/api/java/util/Comparator.html">Comparator</a> would be:</p>
<pre><code>new Comparator&lt;T&gt;() {
  @Override
  public int compare(final T o1, final T o2) {
    // If o1 is "less than" o2, return a negative integer.
    // If o1 is "equal to" o2, return 0.
    // If o1 is "greater than" o2, return a positive integer.
  }
};</code></pre>
<p>In this way, the exact semantics of comparisons can be tailored to meet the needs of the application.  In the case of the Browser Ballot, the team implemented something akin to the following: (Though the language was JavaScript, not Java, as the Browser Ballot was a website)</p>
<pre><code>new Comparator&lt;T&gt;() {
  @Override
  public int compare(final T o1, final T o2) {
    return Math.random() &lt; 0.5 ? 1 : -1;
  }
};</code></pre>
<p>In this comparator, the objects being compared are not even considered; instead the either <code>-1</code> or <code>1</code> is returned with equal probability. Using this sort of &#8220;comparison&#8221; with a sorting algorithm might <em>seem</em> to provide random, unbiased results &#8211; but in reality, such &#8220;common sense&#8221; did not make so much sense after further analysis.</p>
<h2>Looking deeper</h2>
<p>To look at the problem a bit more in-depth, I decided to write an example in Java that would test the results of a &#8220;random sort&#8221; on a set of four objects, using the following sorting algorithms: A modified Merge sort (provided by Java&#8217;s <code><a href="http://docs.oracle.com/javase/6/docs/api/java/util/Collections.html#sort%28java.util.List,%20java.util.Comparator%29">Collections.sort()</a></code>), Quicksort, Insertion sort and Selection sort. These results would then be compared to using the proper method, a Fisher-Yates shuffle.</p>
<p>Some more details:</p>
<ul>
<li>The list to be shuffled started off with the ordering of <code>[1, 2, 3, 4]</code></li>
<li>I used my own implementation of Quicksort that just selected the pivot from the middle of the list.</li>
<li>Bubble sort was not considered, since with a randomized comparator, the algorithm may never terminate!</li>
</ul>
<p>Here are the results:</p>
<p class="image">
<a href="http://unitstep.net/wordpress/wp-content/uploads/2012/02/shuffle-permutation-results.png"><img src="http://unitstep.net/wordpress/wp-content/uploads/2012/02/shuffle-permutation-results-300x298.png" alt="" title="shuffle-permutation-results" width="300" height="298" class="alignnone size-medium wp-image-1361" /></a></p>
<p>As you can see, the Fisher-Yates shuffling algorithm produces the expected near-uniform distribution, represented by the almost-straight line. The &#8220;randomized&#8221; sorting algorithms most definitely did not produce a uniform distribution.  Interestingly, the modified merge sort used by <code>Collections.sort()</code> produced the same distribution as Insertion sort; This may mean that this specific implementation of merge sort uses an insertion sort when the collection size is sufficiently low.</p>
<p>Of the sorting algorithms tested, Quicksort had the least difference between the &#8220;peaks&#8221; and &#8220;troughs&#8221;, though the bias was still very evident. I&#8217;ve heard that Quicksort <em>may</em> produce a near-uniform distribution when used with a randomized comparator, but I&#8217;m guessing that would depend greatly on the choice of pivot.</p>
<h2>Conclusion</h2>
<p>Randomization is never an easy thing; one must fully consider the effects of a specific algorithm before jumping to conclusions as &#8220;common sense&#8221; doesn&#8217;t really make much sense in this area. Come to think of it, &#8220;common sense&#8221; is rarely sensible. </p>
<p>Careful analysis is always needed whenever dealing with distribution of random variables. In general, for a random variable <em>A</em> that has a certain distribution, <em>f(A)</em> is not guaranteed to have the same distribution. This is the point that was missed when designing the ballot. </p>
<p>Analysis of the Fisher-Yates algorithm is fairly easy: The reason why it works is that at each step of selecting an element from the collection, each remaining element has an equally-likely probability of being selected. Analysis of each of the randomized sorting algorithms to understand why each distribution was produced is more difficult, and is left as an exercise to the reader. <img src='http://unitstep.net/wordpress/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' /> </p>
<p>It&#8217;s also worthwhile to note that the correct shuffling algorithm (Fisher-Yates) runs in <em>O(n)</em> time, while all of the randomized sorting algorithms have a longer asymptotic run time.</p>
<hr/>Copyright &copy; 2012 <strong><a href="http://unitstep.net">unitstep.net</a></strong>. This Feed is for personal non-commercial use only. If you are not reading this material in your news aggregator, the site you are looking at is guilty of copyright infringement. Please contact <strong><a href="mailto:webmaster@unitstep.net">webmaster@unitstep.net</a></strong> for more information.<br/><span style="float: right;font-size: 7pt"><a href="http://blog.taragana.com/index.php/archive/wordpress-plugins-provided-by-taraganacom/">Plugin</a> by <a href="http://www.taragana.com/">Taragana</a></span><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/unitstep?a=teJdn-7Xcgg:rVcu-BzMV9o:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/unitstep?i=teJdn-7Xcgg:rVcu-BzMV9o:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=teJdn-7Xcgg:rVcu-BzMV9o:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/unitstep?i=teJdn-7Xcgg:rVcu-BzMV9o:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=teJdn-7Xcgg:rVcu-BzMV9o:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/unitstep?i=teJdn-7Xcgg:rVcu-BzMV9o:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=teJdn-7Xcgg:rVcu-BzMV9o:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/unitstep?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=teJdn-7Xcgg:rVcu-BzMV9o:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/unitstep?d=yIl2AUoC8zA" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/unitstep/~4/teJdn-7Xcgg" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://unitstep.net/blog/2012/02/05/shuffle-sort-and-other-fallacies-of-randomization/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://unitstep.net/blog/2012/02/05/shuffle-sort-and-other-fallacies-of-randomization/</feedburner:origLink></item>
		<item>
		<title>The Flyweight Pattern: (Mis|ab)used at times.</title>
		<link>http://feedproxy.google.com/~r/unitstep/~3/9-cyD9wUWfk/</link>
		<comments>http://unitstep.net/blog/2012/01/08/the-flyweight-pattern-misabused-at-times/#comments</comments>
		<pubDate>Sun, 08 Jan 2012 23:21:10 +0000</pubDate>
		<dc:creator>Peter Chng</dc:creator>
				<category><![CDATA[development]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[tutorials]]></category>
		<category><![CDATA[software development java design-patterns]]></category>

		<guid isPermaLink="false">http://unitstep.net/?p=1312</guid>
		<description><![CDATA[In my brief career in software development thus far, I have seen a lot of &#8220;WTF&#8221; code, that is, code that deserves to be posted to The Daily WTF. Some of this code was admittedly developed by myself and upon reviewing it a few months after it was written, I secretly wondered what I&#8217;d been [...]]]></description>
			<content:encoded><![CDATA[<p>In my brief career in software development thus far, I have seen a lot of &#8220;WTF&#8221; code, that is, code that deserves to be posted to <a href="http://thedailywtf.com/">The Daily WTF</a>. Some of this code was admittedly developed by myself and upon reviewing it a few months after it was written, I secretly wondered what I&#8217;d been thinking.</p>
<p>This isn&#8217;t going to be an indictment of bad programming; in fact, I think it&#8217;s good if you can look back at your old code and see where it could be improved. Such a process suggests that you are continually <em>self-improving</em>, a skill crucial in software development. Besides, all of us have made a mistake or two at times when we were stressed, tired or just plain not thinking straight.</p>
<p>However, there&#8217;s one mistake that I&#8217;ve seen that I think warrants bringing to light, and that is the misuse of the <em>Flyweight pattern</em>.</p>
<h2>Who wants to be a Flyweight?</h2>
<p>Flyweight is typically used to describe one of the smaller weight classes in boxing or other fighting sports. This &#8220;minimal&#8221; aspect is what is shared with the design pattern of the same name. Simply put, a Flyweight object is one that reduces memory use by sharing common data with other objects.  Despite this plain definition, implementing the Flyweight pattern can be tricky.</p>
<p>Perhaps this is why I have seen examples like this: (<em>Java pseudo-code below; may not compile, but you shouldn&#8217;t use it anyways</em>)</p>
<pre><code>public class WidgetWithManyFields() {
  private Data field1;
  private String field2;
  private int field3;
  // A lot more fields...
  private SomeOtherData fieldN;

  // Getters and setters...
}</code></pre>
<p>Now, obviously the memory footprint of <code>WidgetWithManyFields</code> can be quite large, and since not all aspects of an application will need access to all data fields, it was decided that a &#8220;Flyweight&#8221; was needed:</p>
<pre><code>public class WidgetFlyweight() {
  // Only these fields are needed.
  private Data field1;
  private String field2;

  public WidgetFlyweight() {
    // Default constructor.
  }

  // Constructor to make one from the regular widget class.
  public WidgetFlyweight(WidgetWithManyFields widget) {
    this.field1 = widget.getField1();
    this.field2 = widget.getField2();
  }
  // Getters and setters...
}</code></pre>
<p>This isn&#8217;t really the Flyweight pattern at all. In fact, I don&#8217;t even know if it is a pattern at all. It might be considered something like the Proxy pattern, <em>if</em> the &#8220;Flyweight&#8221; class contained an instance of the regular class. But I don&#8217;t really know.</p>
<h2>So what is a Flyweight?</h2>
<p>Consider the example of a document that can have images embedded in it. There might be multiple copies of the same image present in the document, but each copy would be sized and positioned differently within the document. </p>
<p>In this case, you wouldn&#8217;t want to load and store the data in memory for multiple copies of the same image as that would be wasteful. However, each instance of the image displayed in the document might be formatted or positioned differently. How might this be done?</p>
<p>Firstly, some assumptions:</p>
<ul>
<li>An image is uniquely identified by some resource path.</li>
<li>The underlying image data does not change during the lifetime of the application.</li>
</ul>
<p>With these assumptions, we can define three classes that allow us to implement the Flyweight pattern.</p>
<p>Firstly, an <code>ImageData</code> class that encapsulates the actual image data. There should be only one canonical instance of this class for each unique resource path. Because of this, we can pool these objects for reuse.</p>
<p>However, the <code>ImageData</code> objects won&#8217;t be directly used by other parts of the application. Instead, we create an <code>ImageFlyweight</code> class that is manipulated. Each instance contains a reference to a canonical <code>ImageData</code> object and also stores information about how to format and position the image.</p>
<p>In this way, there can be multiple <code>ImageFlyweight</code> instances that reference the same image and hence the same <code>ImageData</code> instance, but each instance would define separate formatting and positioning details.</p>
<p>Tying everything together is a factory (<code>ImageFlyweightFactory</code>) that maintains the pool and is the access point for getting instances of <code>ImageFlyweight</code>.</p>
<p>Below is the code: (Sorry, it&#8217;s a lot of code to throw at you at once, but I didn&#8217;t feel like breaking it down into separate chunks, and you can just copy &#038; paste it into your favourite IDE for inspection/compilation)</p>
<pre><code>/**
 * Copyright (c) 2012 Peter Chng, http://unitstep.net/
 */
package net.unitstep.examples.flyweight;

import java.util.HashMap;
import java.util.Map;

/**
 * In order for the Flyweight Pattern to be effective, ImageFlyweight instances
 * should only be obtained via ImageFlyweightFactory.getImageFlyweight().
 *
 * This ensures that for each unique resource path, there is only one instance
 * of the backing ImageData existing in the application.
 *
 * @author Peter Chng
 */
public class ImageFlyweightFactory {
  private Map&lt;String, ImageData&gt; imageDataPool =
      new HashMap&lt;String, ImageData&gt;();

  public ImageFlyweight getImageFlyweight(final String resourcePath) {
    // This will return a new ImageFlyweight object each time; however, the
    // backing ImageData might be shared across multiple ImageFlyweight
    // instances.
    return new ImageFlyweight(this.getImageData(resourcePath));
  }

  private ImageData getImageData(final String resourcePath) {
    ImageData imageData = this.imageDataPool.get(resourcePath);
    if (null == imageData) {
      imageData = new ImageData(resourcePath);
      this.imageDataPool.put(resourcePath, imageData);
    }
    return imageData;
  }

  /**
   * @return the current count of ImageData instances in the pool; only for
   *         testing purposes.
   */
  public int getImageDataPoolCount() {
    return this.imageDataPool.size();
  }

  /**
   * Will contain the data representing an image loaded from some resource, i.e.
   * the file system.
   *
   * This is a private inner class because it should never need to be used
   * externally by callers. It is considered an implementation detail.
   *
   * We assume that the resource path is the uniquely-identifying aspect of an
   * image and that the underlying image resource/data will not change over the
   * lifetime of the application.
   *
   * Thus, only one instance of the ImageData class is needed for each image
   * uniquely identified by its resource path.
   *
   * @author Peter Chng
   */
  private class ImageData {
    private final byte[] data;
    private final String resourcePath;

    public ImageData(final String resourcePath) {
      this.resourcePath = resourcePath;

      // Image data would be loaded here based on the resource path supplied.
      // For brevity, it's not really done.
      this.data = new byte[] {};
    }

    public byte[] getData() {
      // Note: If we really intend to make this class immutable, we should
      // return a defensive copy instead so that callers cannot modify the
      // data stored in this instance.
      return this.data;
    }

    public String getResourcePath() {
      return resourcePath;
    }

    // Note: Not strictly necessary to override equals() and hashCode() for this
    // example, but it's done to indicate we only consider the resource path
    // in determining equality.
    @Override
    public boolean equals(final Object object) {
      if (null == object) {
        return false;
      }
      if (object == this) {
        return true;
      }
      if (object.getClass() != this.getClass()) {
        return false;
      }
      return this.resourcePath.equals(((ImageData) object).getResourcePath());
    }

    @Override
    public int hashCode() {
      return this.resourcePath.hashCode();
    }
  }

  /**
   * The ImageFlyweight object contains a reference to a canonical ImageData
   * object containing the actual image data we wish to render.
   *
   * By making this a static inner class of {@link ImageFlyweightFactory} and
   * the constructor private, instantiation of this class can be controlled and
   * limited to only the {@link ImageFlyweightFactory}. Callers MUST obtain an
   * instance of the ImageFlyweight through the factory and not by direct
   * instantiation.
   *
   * It also contains other properties that will affect the rendering of the
   * image in the application, such as height, width and position.
   *
   * Reusing the same ImageData object across different ImageFlyweight instances
   * allows us to display the same image in different ways within the
   * application, without having to load (or store in memory) the image data
   * multiple times.
   *
   * @author Peter Chng
   */
  public static class ImageFlyweight {
    private final ImageData imageData;

    private int height;
    private int width;
    private int positionX;
    private int positionY;

    private ImageFlyweight(final ImageData imageData) {
      this.imageData = imageData;
    }

    public byte[] getData() {
      return this.imageData.getData();
    }

    // Getters/setters for height, width, positionX, positionY...

    public int getHeight() {
      return height;
    }

    public void setHeight(int height) {
      this.height = height;
    }

    public int getWidth() {
      return width;
    }

    public void setWidth(int width) {
      this.width = width;
    }

    public int getPositionX() {
      return positionX;
    }

    public void setPositionX(int positionX) {
      this.positionX = positionX;
    }

    public int getPositionY() {
      return positionY;
    }

    public void setPositionY(int positionY) {
      this.positionY = positionY;
    }
  }
}</code></pre>
<p>Everything is contained within the <code>ImageFlyweightFactory</code> class, because the <code>ImageData</code> class does not need to be visible to outsiders and callers should not be able to instantiate <code>ImageFlyweight</code> instances on their own.</p>
<p>With this code, we have a simple test harness to verify whether it&#8217;s working:</p>
<pre><code>/**
 * Copyright (c) 2012 Peter Chng, http://unitstep.net/
 */
package net.unitstep.examples.flyweight;

import net.unitstep.examples.flyweight.ImageFlyweightFactory.ImageFlyweight;

import org.apache.log4j.Logger;

/**
 * @author Peter Chng
 */
public class ImageFlyweightTest {

  private static final Logger LOGGER =
      Logger.getLogger(ImageFlyweightTest.class);

  public static void main(final String[] args) {
    final ImageFlyweightFactory factory = new ImageFlyweightFactory();

    final String resourcePath1 = "/path/to/images/someImage.png";
    final String resourcePath2 = "/path/to/images/anotherImage.png";

    final ImageFlyweight image1 = factory.getImageFlyweight(resourcePath1);

    displayImageDataCountInPool(factory);

    final ImageFlyweight image2 = factory.getImageFlyweight(resourcePath2);

    displayImageDataCountInPool(factory);

    // Should not create an new ImageData instance in the pool.
    final ImageFlyweight image3 = factory.getImageFlyweight(resourcePath1);

    displayImageDataCountInPool(factory);
  }

  private static void displayImageDataCountInPool(
      final ImageFlyweightFactory factory) {
    LOGGER.debug("Current number of ImageData instances: "
        + factory.getImageDataPoolCount());
  }
}</code></pre>
<p>Running the code yields the following results:</p>
<pre>
DEBUG ImageFlyweightTest - Current number of ImageData instances: 1
DEBUG ImageFlyweightTest - Current number of ImageData instances: 2
DEBUG ImageFlyweightTest - Current number of ImageData instances: 2
</pre>
<p>The key point is that after the third <code>ImageFlyweight </code> object is created, the count in the <code>ImageData</code> pool does not increase since the same image has already been &#8220;loaded&#8221;.</p>
<h2>Other examples</h2>
<p>Note that Java itself implements something similar to the Flyweight pattern for Strings; this is known as <em>string interning</em> and many other languages support this feature as well.</p>
<p>Basically, because Strings are immutable, Java can store each distinct value in a pool and then reuse these instances when appropriate.  As an example, the following code displays &#8220;EQUAL&#8221;:</p>
<pre><code>String string1 = "A test of the string intern pool.";
String string2 = "A test of the string intern pool.";
// Note that we are comparing object identity, NOT equality.
if (string1 == string2) {
  System.out.println("EQUAL");
} else {
 System.out.println("NOT EQUAL");
}</code></pre>
<p>Note that this doesn&#8217;t work if you directly create a String using the <code>new</code> keyword.</p>
<h2>Conclusion</h2>
<p>I know that this was a fairly contrived example (aren&#8217;t they all?), but I hope it provided the basics of the Flyweight pattern to readers. There are a lot of holes and I don&#8217;t suggest you directly copy this example for production code, but instead learn the skills to effectively develop the pattern on your own.</p>
<p>As always, I welcome questions or comments and especially corrections if I&#8217;ve made a mistake! Thanks for reading!</p>
<hr/>Copyright &copy; 2012 <strong><a href="http://unitstep.net">unitstep.net</a></strong>. This Feed is for personal non-commercial use only. If you are not reading this material in your news aggregator, the site you are looking at is guilty of copyright infringement. Please contact <strong><a href="mailto:webmaster@unitstep.net">webmaster@unitstep.net</a></strong> for more information.<br/><span style="float: right;font-size: 7pt"><a href="http://blog.taragana.com/index.php/archive/wordpress-plugins-provided-by-taraganacom/">Plugin</a> by <a href="http://www.taragana.com/">Taragana</a></span><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/unitstep?a=9-cyD9wUWfk:w_DbXRwYXzc:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/unitstep?i=9-cyD9wUWfk:w_DbXRwYXzc:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=9-cyD9wUWfk:w_DbXRwYXzc:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/unitstep?i=9-cyD9wUWfk:w_DbXRwYXzc:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=9-cyD9wUWfk:w_DbXRwYXzc:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/unitstep?i=9-cyD9wUWfk:w_DbXRwYXzc:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=9-cyD9wUWfk:w_DbXRwYXzc:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/unitstep?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=9-cyD9wUWfk:w_DbXRwYXzc:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/unitstep?d=yIl2AUoC8zA" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/unitstep/~4/9-cyD9wUWfk" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://unitstep.net/blog/2012/01/08/the-flyweight-pattern-misabused-at-times/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://unitstep.net/blog/2012/01/08/the-flyweight-pattern-misabused-at-times/</feedburner:origLink></item>
		<item>
		<title>Goodbye, old friend…</title>
		<link>http://feedproxy.google.com/~r/unitstep/~3/5uLoqdDPQZw/</link>
		<comments>http://unitstep.net/blog/2011/12/15/goodbye-old-friend/#comments</comments>
		<pubDate>Thu, 15 Dec 2011 23:25:09 +0000</pubDate>
		<dc:creator>Peter Chng</dc:creator>
				<category><![CDATA[asides]]></category>
		<category><![CDATA[Life]]></category>
		<category><![CDATA[glasses]]></category>

		<guid isPermaLink="false">http://unitstep.net/?p=1304</guid>
		<description><![CDATA[I&#8217;ve had the same pair of prescription glasses since about 2004, having changed the lens more than once. I just got so used to them that whenever the opportunity arose to replace them, I couldn&#8217;t find a pair that felt or looked right. So, I just continued with the same old dependable pair. They&#8217;ve fallen [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve had the same pair of prescription glasses since about 2004, having changed the lens more than once. I just got so used to them that whenever the opportunity arose to replace them, I couldn&#8217;t find a pair that felt or looked right. So, I just continued with the same old dependable pair.</p>
<p>They&#8217;ve fallen off of my face more than once, have tumbled many times to the hardwood floor from my nightstand while I fumbled for them in the dark, been lost in my bed covers and rolled onto during numerous occasions, and of course I&#8217;ve fallen asleep with them on more times than I can remember. Despite all of this, they not only held together, but retained much of the original lustre and remain in excellent condition.</p>
<p>Only one of the earpieces is starting to look worn, the nose pads are looking a little old and one of the lens screws had to be replaced when it fell out and got lost, but other than that, they&#8217;re as good as new. This was the first &#8220;thin&#8221; pair of glasses I had ever worn and I initially had some reservations about durability, so I&#8217;m more than pleased with how well they&#8217;ve held up. (I think the frames are made up of some titanium, but I can&#8217;t remember)</p>
<p>But this past weekend, I decided it was time to finally replace them. </p>
<p class="image">
<a href="http://unitstep.net/wordpress/wp-content/uploads/2011/12/eyeglasses.jpg"><img src="http://unitstep.net/wordpress/wp-content/uploads/2011/12/eyeglasses-300x225.jpg" alt="" title="Old eyeglasses" width="300" height="225" class="alignnone size-medium wp-image-1318" /></a>
</p>
<p>We&#8217;ve had a good run, old friend, but I&#8217;m afraid it&#8217;s time to part ways.</p>
<p>I went down to the local Pearle Vision since it was close and seemed to have a decent selection of frames. In fact, I found there was just too many options. Many of them were easily ruled out, but I still ended up spending over an hour trying on frames with fingerprints and smudges all over the lenses in an effort to find the right pair. Or, rather, the right <em>pairs</em>, since they had this screwed up pricing that basically forced you to buy two pairs at once since you hardly saved anything by buying a single pair.</p>
<p>The problem with selecting glasses (besides my indecisiveness, aggravated by the multitude of options) is that it&#8217;s hard to know how well they&#8217;ll do or look over the long run. Durability is important to me, and certainly some frames &#8220;felt&#8221; more durable than others, but that&#8217;s not really a sound way of assessing things. I guess I&#8217;m just expecting these new frames to last as long as the previous ones did, because I find it hard to change &#8220;styles&#8221;.</p>
<p>The other problem is that it&#8217;s hard to tell what you look like in them if you don&#8217;t wear contacts &#8211; thankfully this isn&#8217;t a problem for me; I&#8217;d be nearly blind without corrective vision.</p>
<p>Eventually, if you try on enough frames and stay in the store for long enough, almost all glasses start to look acceptable. This is because style and attractiveness are both subjective and tend to be swayed one way or another by overexposure. It&#8217;s almost as if your subconscious is overriding your critical thinking in an effort to get you out of the store and on your way. </p>
<p>You need to know when this effect is taking a hold of you, so I suggest the following: Within five minutes of entering the store, identify and try on a pair of frames that look utterly ridiculous on you. Then, put these back; don&#8217;t worry, you definitely won&#8217;t be getting these. After you&#8217;ve been in the store for an hour or so, and you&#8217;re noticing that most frames you&#8217;re trying on are looking good, go back and try on the hideous pair.</p>
<p>If the hideous pair now look attractive or even slightly better than before, your judgment has already been compromised. Either leave and come back another day or take your chances with a pair that you found attractive <em>early on</em> during your search. This is what I did.</p>
<p>I should be getting the new frames within a few days. Hopefully I wasn&#8217;t judgment-impaired when I made my choice.</p>
<hr/>Copyright &copy; 2012 <strong><a href="http://unitstep.net">unitstep.net</a></strong>. This Feed is for personal non-commercial use only. If you are not reading this material in your news aggregator, the site you are looking at is guilty of copyright infringement. Please contact <strong><a href="mailto:webmaster@unitstep.net">webmaster@unitstep.net</a></strong> for more information.<br/><span style="float: right;font-size: 7pt"><a href="http://blog.taragana.com/index.php/archive/wordpress-plugins-provided-by-taraganacom/">Plugin</a> by <a href="http://www.taragana.com/">Taragana</a></span><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/unitstep?a=5uLoqdDPQZw:6yeDnBQ32Vo:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/unitstep?i=5uLoqdDPQZw:6yeDnBQ32Vo:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=5uLoqdDPQZw:6yeDnBQ32Vo:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/unitstep?i=5uLoqdDPQZw:6yeDnBQ32Vo:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=5uLoqdDPQZw:6yeDnBQ32Vo:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/unitstep?i=5uLoqdDPQZw:6yeDnBQ32Vo:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=5uLoqdDPQZw:6yeDnBQ32Vo:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/unitstep?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=5uLoqdDPQZw:6yeDnBQ32Vo:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/unitstep?d=yIl2AUoC8zA" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/unitstep/~4/5uLoqdDPQZw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://unitstep.net/blog/2011/12/15/goodbye-old-friend/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://unitstep.net/blog/2011/12/15/goodbye-old-friend/</feedburner:origLink></item>
		<item>
		<title>Boston reflection and updates</title>
		<link>http://feedproxy.google.com/~r/unitstep/~3/AyFyEMp795o/</link>
		<comments>http://unitstep.net/blog/2011/06/19/boston-reflection-and-updates/#comments</comments>
		<pubDate>Sun, 19 Jun 2011 18:05:00 +0000</pubDate>
		<dc:creator>Peter Chng</dc:creator>
				<category><![CDATA[asides]]></category>
		<category><![CDATA[Life]]></category>
		<category><![CDATA[marathon]]></category>
		<category><![CDATA[running]]></category>
		<category><![CDATA[boston marathon]]></category>

		<guid isPermaLink="false">http://unitstep.net/?p=1280</guid>
		<description><![CDATA[It&#8217;s been two months since the 2011 Boston Marathon, which was my first attempt at this historic race. As some of you may know, it had been one of the focal points of my life for the past several months, ever since I qualified by 13 seconds back in September of 2010. I took a [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s been two months since the <a href="http://www.baa.org/races/boston-marathon.aspx">2011 Boston Marathon</a>, which was my first attempt at this historic race. As some of you may know, it had been one of the focal points of my life for the past several months, <a href="/blog/2010/10/09/qualified-for-the-boston-marathon/">ever since I qualified by 13 seconds</a> back in September of 2010.</p>
<p>I took a <a href="/blog/2011/01/16/what-ive-been-up-to/">new approach to training</a> and really dedicated myself to it. There were many mid-week 4 AM mornings, followed by 1.5-2 hour runs in the dark, snow/rain and wind. I arrived at the starting line being as prepared for any race as I&#8217;d ever been.</p>
<p>However, I failed to meet my goal time of a sub-3:03 marathon, finishing in only 3:07:20. I made several mistakes early on and fell behind the pace within the first 10 km. However, I was most disappointed in myself for not pushing harder. I felt that I had mentally &#8220;checked out&#8221; after the first half, and consciously or not, believed that meeting my goal was now impossible due to the early mistakes. Because of that, I felt that I didn&#8217;t try as hard as I could and that I did not give 100% for fear of failure. It was almost as if I had sabotaged myself into thinking, &#8220;If I don&#8217;t give 100% and miss my goal, well at least then I will have an excuse.&#8221;</p>
<p>I fell into a pretty big slump after Boston and didn&#8217;t/couldn&#8217;t run for almost a week after. Even when I did start again, things just weren&#8217;t the same &#8211; my confidence had been shattered. I knew I had to break out of this slump, so I signed up for the <a href="http://www.mississaugamarathon.com/default.shtml">Mississauga Half Marathon</a>, which was about a month after Boston, to give me something to shoot for.</p>
<p>Why the half? Simply put, I didn&#8217;t think I&#8217;d be ready for another full so soon &#8211; not just physically, but mentally as well. If I were to run the full, I would have wanted to aim for a sub-3:05, in order to get in on the <a href="http://www.baa.org/races/boston-marathon/participant-information/register.aspx">first week of registration for 2012</a>. However, I didn&#8217;t feel that I would have the mental toughness required to meet that time and couldn&#8217;t deal with the heartbreak of another missed goal. So, I decided on the half, a distance I felt comfortable with.</p>
<p>Things turned out great &#8211; though the conditions were looking windy/rainy, things actually were not that bad, and I was able to pull of a huge PR, finishing in a time of 1:24:02 in the Mississauga Half Marathon, well ahead of any goal I&#8217;d had. This was good enough for 4th in my age group. Suffice to say, this was a huge confidence booster, something I sorely needed. </p>
<h2>Edmonton Marathon</h2>
<p>Coming off my performance at the Mississauga Half, I felt elated and immediately signed up for the Edmonton Marathon, which takes place on August 21st of this year. This would give me two weeks of downtime before I would have to start a 12-week training schedule for it. 12 weeks might seem a little short, but I actually think it&#8217;s pretty close to optimal considering my present situation. I felt that the 18-week program I used for Boston was perhaps a little long, and something between 14-16 weeks would have been better. </p>
<p>Given that I&#8217;m coming off a good base established by my Boston training (though not reflected in my performance there, but instead at the Mississauga Half), I feel that 12 weeks is more than enough to be ready for Edmonton, provided I stick to the plan, rest/recovery well and not over do things.</p>
<p>Edmonton will be my last chance to qualify for Boston 2012, since registration starts in early September. Technically, I&#8217;m already &#8220;qualified&#8221; for Boston 2012, but I don&#8217;t believe my time will be fast enough to actually allow my entry accepted. Complicated story aside, most runners I&#8217;ve talked to have thought that you&#8217;ll need to have at least BQ-5 (that is, your Boston Qualification time minus 5 minutes) in order to have a chance to get in, so I&#8217;ll be aiming for a sub-3:05 finish.</p>
<p>Running a marathon is no easy task. You train for months and basically have once chance to prove yourself. I don&#8217;t deal well with pressure, and I choked at Boston this year. I&#8217;m trying to avoid that this time in Edmonton.</p>
<p>Edmonton has the advantage of being a flat course, and the climate is not known for its hot summers. When I ran it back in 2009, the starting line temperature was only around 8C with a finishing temperature of 16C. This is pretty close to ideal. However, there are only so many things one can control.</p>
<p>Training doesn&#8217;t guarantee any performance; it can only increase the chances of reaching your desired goal. I have accepted the fact that I may give 100% this time and again fail to meet my goal &#8211; that is just part of the game. You can&#8217;t be afraid to fail if you want to achieve something.</p>
<h2>Site updates</h2>
<p>Yet again, I&#8217;ve fallen behind with keeping this site up to date with articles and guides. It&#8217;s not that I don&#8217;t have any ideas, it&#8217;s just that I&#8217;ve been lazy to make the time to put them together. A combination of work, training and life has yet again provided me with the excuse to not further this site with articles that may be of importance to readers. </p>
<p>Writing tutorials and other informational articles is as much a help to me as it is to those who read them, so I will be putting more effort towards this. I hope that you have enjoyed the few that I have written this year.</p>
<hr/>Copyright &copy; 2012 <strong><a href="http://unitstep.net">unitstep.net</a></strong>. This Feed is for personal non-commercial use only. If you are not reading this material in your news aggregator, the site you are looking at is guilty of copyright infringement. Please contact <strong><a href="mailto:webmaster@unitstep.net">webmaster@unitstep.net</a></strong> for more information.<br/><span style="float: right;font-size: 7pt"><a href="http://blog.taragana.com/index.php/archive/wordpress-plugins-provided-by-taraganacom/">Plugin</a> by <a href="http://www.taragana.com/">Taragana</a></span><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/unitstep?a=AyFyEMp795o:dA99KSdoU94:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/unitstep?i=AyFyEMp795o:dA99KSdoU94:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=AyFyEMp795o:dA99KSdoU94:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/unitstep?i=AyFyEMp795o:dA99KSdoU94:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=AyFyEMp795o:dA99KSdoU94:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/unitstep?i=AyFyEMp795o:dA99KSdoU94:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=AyFyEMp795o:dA99KSdoU94:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/unitstep?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=AyFyEMp795o:dA99KSdoU94:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/unitstep?d=yIl2AUoC8zA" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/unitstep/~4/AyFyEMp795o" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://unitstep.net/blog/2011/06/19/boston-reflection-and-updates/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://unitstep.net/blog/2011/06/19/boston-reflection-and-updates/</feedburner:origLink></item>
		<item>
		<title>Excess packaging</title>
		<link>http://feedproxy.google.com/~r/unitstep/~3/eVR-VlJub6Q/</link>
		<comments>http://unitstep.net/blog/2011/05/28/excess-packaging/#comments</comments>
		<pubDate>Sat, 28 May 2011 14:12:49 +0000</pubDate>
		<dc:creator>Peter Chng</dc:creator>
				<category><![CDATA[asides]]></category>
		<category><![CDATA[batteries]]></category>
		<category><![CDATA[dell]]></category>
		<category><![CDATA[packaging]]></category>

		<guid isPermaLink="false">http://unitstep.net/?p=1270</guid>
		<description><![CDATA[I recently ordered some extra Sanyo eneloop batteries when they were on sale at Dell. They&#8217;re great rechargeables, but I don&#8217;t know why most packages always come with a charger &#8211; I now have three of them from previous purchases. However, when I received the package from Dell, I was surprised at the size. It [...]]]></description>
			<content:encoded><![CDATA[<p>I recently ordered some extra Sanyo eneloop batteries when they were on sale at Dell. They&#8217;re great rechargeables, but I don&#8217;t know why most packages always come with a charger &#8211; I now have three of them from previous purchases.</p>
<p>However, when I received the package from Dell, I was surprised at the size. It came in a huge 18&#8243;x13&#8243; bubble envelope:</p>
<p class="image">
<a href="http://www.zooomr.com/photos/stygiansonic/9947217/" title="Photo Sharing"><img src="http://static.zooomr.com/images/9947217_eefd83418b_m.jpg" width="240" height="180" alt="Dell packaging" /></a></p>
<p>I thought it was just excess shipping packaging, but opening the enveloped made it clear that the packaging was only just big enough to hold the actual item:</p>
<p class="image"><a href="http://www.zooomr.com/photos/stygiansonic/9947222/" title="Photo Sharing"><img src="http://static.zooomr.com/images/9947222_75aaefa95e_m.jpg" width="240" height="180" alt="Huge eneloop package" /></a></p>
<p class="image"><a href="http://www.zooomr.com/photos/stygiansonic/9947226/" title="Photo Sharing"><img src="http://static.zooomr.com/images/9947226_b2fa56a4f3_m.jpg" width="240" height="180" alt="Green packaging?" /></a></p>
<p>For batteries with packaging that seems to imply they&#8217;re good for the environment, you think they would have made the packaging a little less excessive. The packaging is still 100% recyclable, but it still costs energy to make it.</p>
<p>At least Dell didn&#8217;t put the already-large item in a huge shipping box.</p>
<hr/>Copyright &copy; 2012 <strong><a href="http://unitstep.net">unitstep.net</a></strong>. This Feed is for personal non-commercial use only. If you are not reading this material in your news aggregator, the site you are looking at is guilty of copyright infringement. Please contact <strong><a href="mailto:webmaster@unitstep.net">webmaster@unitstep.net</a></strong> for more information.<br/><span style="float: right;font-size: 7pt"><a href="http://blog.taragana.com/index.php/archive/wordpress-plugins-provided-by-taraganacom/">Plugin</a> by <a href="http://www.taragana.com/">Taragana</a></span><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/unitstep?a=eVR-VlJub6Q:38ZiQA26-w0:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/unitstep?i=eVR-VlJub6Q:38ZiQA26-w0:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=eVR-VlJub6Q:38ZiQA26-w0:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/unitstep?i=eVR-VlJub6Q:38ZiQA26-w0:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=eVR-VlJub6Q:38ZiQA26-w0:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/unitstep?i=eVR-VlJub6Q:38ZiQA26-w0:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=eVR-VlJub6Q:38ZiQA26-w0:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/unitstep?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=eVR-VlJub6Q:38ZiQA26-w0:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/unitstep?d=yIl2AUoC8zA" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/unitstep/~4/eVR-VlJub6Q" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://unitstep.net/blog/2011/05/28/excess-packaging/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://unitstep.net/blog/2011/05/28/excess-packaging/</feedburner:origLink></item>
		<item>
		<title>Java, Weak References and WeakHashMap</title>
		<link>http://feedproxy.google.com/~r/unitstep/~3/0bc-Nt2yHp8/</link>
		<comments>http://unitstep.net/blog/2011/03/26/java-weak-references-and-weakhashmap/#comments</comments>
		<pubDate>Sat, 26 Mar 2011 16:27:19 +0000</pubDate>
		<dc:creator>Peter Chng</dc:creator>
				<category><![CDATA[guides]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[references]]></category>
		<category><![CDATA[weakhashmap]]></category>

		<guid isPermaLink="false">http://unitstep.net/?p=1229</guid>
		<description><![CDATA[Most any Java Developer will be familiar with the concepts of references, as in pass-by-reference vs. pass-by-value. (Pointers, now that&#8217;s another thing&#8230;) When calling methods, primitive data types are passed by value, while objects and arrays are passed by reference. This means when you call a method with an object as a parameter, you are [...]]]></description>
			<content:encoded><![CDATA[<p>Most any Java Developer will be familiar with the concepts of <em>references</em>, as in pass-by-reference vs. pass-by-value. (Pointers, now that&#8217;s another thing&#8230;)</p>
<p>When calling methods, primitive data types are passed by value, while objects and arrays are passed by reference. This means when you call a method with an object as a parameter, you are merely providing that method a way to access/manipulate the <em>same</em> object via a reference; no copy is made. Contrast that with primitives: When calling a method that requires them, a copy of that value is put on the call stack before invoking the method.</p>
<p>In that way, references are somewhat like pointers, though they obviously cannot be manipulated by pointer arithmetic.  But what about <strong>weak references</strong>? What are they, and how do they contrast with <em>strong</em> references?</p>
<h2>Weakly understood</h2>
<p>Based on my experience, the concept of weak references, or more generally reachability, is not one that is well-understood in the Java world. At least I did not have a good grasp of them until stumbling upon some sample code one day. It may be that the need to utilize them is outside the confines of most day-to-day programming tasks, as the concept is fairly low-level.  Nonetheless, it&#8217;s an important concept to understand.</p>
<p>Basically, Java specifies five levels of reachability for objects that reflect which state the object is in, in relation to being marked as finalizable, being finalized and being reclaimed.  They are, in order of strongest-to-weakest:</p>
<ol>
<li>Strongly Reachable</li>
<li>Softly Reachable</li>
<li>Weakly Reachable</li>
<li>Phantom Reachable</li>
<li>Unreachable</li>
</ol>
<p>An object&#8217;s normal state, as soon as it has been instantiated and assigned to a variable/field is <em>strongly reachable</em>. Chances are, these are the only types of objects you&#8217;ve worked with.  We&#8217;ll first cover the concept of <em>weakly reachable</em> objects, as I believe it provides a good base for understanding the remainder.</p>
<h2>Cleaning out the trash</h2>
<p>Going by the <a href="http://download.oracle.com/javase/1.5.0/docs/api/java/lang/ref/package-summary.html#reachability">API reference</a>, a weakly reachable object is one that can be reached by traversing (i.e. going through) a weak reference. That&#8217;s a succinct definition to be sure, but it just raises the next question: What is a weak reference?</p>
<p>Simply put, if an object can only be reached by traversing a weak reference, the garbage collector <strong>will not attempt to keep the object in memory any more than it would an object with no references to it</strong>, i.e. an object that cannot be accessed. Thus, from the garbage collector&#8217;s point-of-view, a weakly-referenced object will eventually be cleaned from memory the same as an object no references to it.</p>
<p>So, if weakly-referenced objects are treated the same as completely non-referenced ones, what is the purpose of the weak reference? A good example is the <a href="http://download.oracle.com/javase/6/docs/api/java/util/WeakHashMap.html">WeakHashMap</a>, a class provided by Java.</p>
<h2>WeakHashMap</h2>
<p>Unfortunately, <code>WeakHashMap</code> may also be poorly understood, probably as a result of weak references not being well known. WeakHashMap may at times be described as a &#8220;cache&#8221; of sorts, where objects/entries that are not used will be removed to decrease memory usage. This is not how WeakHashMap works at all.</p>
<p>The best way to describe a WeakHashMap is one where the entries (key-to-value mappings) will be removed when it is no longer possible to retrieve them from the map. For example, say you&#8217;ve added an object to the WeakHashMap using a key <em>k1</em>. If you now set <em>k1</em> to null, there should be no way to retrieve the object from the map, since you don&#8217;t have the key object around any more to call <code>get()</code> with.  This behaviour is possible because WeakHashMap only has weak references to the keys, not strong references like the other Map classes.</p>
<p>Note that for the WeakHashMap to work this way, as it was intended, the key objects must only be considered equal if they are actually the same object &#8211; i.e. object identity instead of mere equality. This is the default behaviour for <code>Object.equals()</code> and <code>Object.hashCode()</code>, so if these methods have not been overridden, the object is OK to be used as a key in WeakHashMap. Objects like <code>Integer</code> are not suitable for use in WeakHashMap, because it is possible to create two separate (non-identical) objects that are both equal:</p>
<pre><code>final Integer i1 = new Integer(4);
final Integer i2 = new Integer(4);
LOGGER.debug("i1.equals(i2): " + i1.equals(i2)); // True.
LOGGER.debug("i1 == i2: " + (i1 == i2)); // False.</code></pre>
<p>Another point of importance is that <code>String</code> is not a suitable key for a WeakHashMap as well. In addition to its overriding of <code>equals()</code> and <code>hashCode()</code>, String objects in Java are also interned (i.e. stored) in a pool by the JVM when created.  This means that they may remain strongly referenced even after you have apparently gotten rid of your reference to them.  Because of this, entries that you add to a WeakHashMap using String keys may never get dropped, even after you have apparently lost reference to the keys, since the Strings may remain strongly referenced in the string intern pool.</p>
<p>An example of String interning:</p>
<pre><code>final String s1 = "The only thing we have to fear is fear itself.";
final String s2 = "The only thing we have to fear is fear itself.";
LOGGER.debug("s1.equals(s2): " + s1.equals(s2)); // True.
LOGGER.debug("s1 == s2: " + (s1 == s2)); // May also return true!</code></pre>
<p>String objects are interned for performance reasons, so when you are going to create a new String, Java first checks if there is a String in the pool that is &#8220;equal&#8221; to the one you are creating.  If such a String exists, the existing object is just returned instead of having to instantiate a new object.  This is possible because Strings in Java are immutable, i.e. operations that appear to modify a String (such as concatenation, <code>toUpperCase()</code>, etc.) really return a new String object while preserving the original.</p>
<p>The last usage note is that even though the keys are weakly-referenced by WeakHashMap, the values remain strongly-referenced. Thus, you must take care to not use value objects that strongly reference the keys themselves, as if this happens, the keys/entries will no longer be automatically dropped because a strong reference may always exist to the keys. (This can be avoided by wrapping the value object in a <a href="http://download.oracle.com/javase/6/docs/api/java/lang/ref/WeakReference.html">WeakReference</a>, so that both keys and values are weakly-referenced when in the WeakHashMap)</p>
<h2>Example use of WeakHashMap</h2>
<p>Here is a brief, albeit contrived example of <code>WeakHashMap</code> at work:</p>
<pre><code>// SampleKey is just an object that holds a single int. (Use instead of
// Integer, since Integer overrides equals() and hashcode())
SampleKey key = new SampleKey(42);
SampleObject value = new SampleObject("Sample Value");

final WeakHashMap&lt;SampleKey, SampleObject&gt; weakHashMap = new WeakHashMap&lt;SampleKey, SampleObject&gt;();
weakHashMap.put(key, value);

// At this point, we still have a strong reference to the key. Thus, even
// though the key is weakly-referenced by the WeakHashMap, nothing will
// be automatically removed even if we give a hint to the GC.
System.gc();

LOGGER.debug(weakHashMap.size()); // Will still be '1'.
LOGGER.debug(weakHashMap.get(key)); // Will still be 'Sample Value'.

// Now, we if set the key to null, the entry in weakHashMap will eventually
// disappear. Note that the number of times we have to 'kick' the GC
// before the entry disappears may be different on each run depending
// on the JVM load, memory usage, etc.
key = null;
int count = 0;
while(0 != weakHashMap.size())
{
  ++count;
  System.gc();
}
LOGGER.debug("Took " + count + " calls to System.gc() to result in weakHashMap size of : " + weakHashMap.size());</code></pre>
<h2>Finishing up</h2>
<p>In an upcoming article, I plan on covering the other types of references (soft and phantom) as well as the associated <code>Reference</code> classes in Java. I wanted to keep this post brief so that it provided a basic understanding of the situation.</p>
<h4>Changes/Fixes</h4>
<ul>
<li><strong>2011-04-10</strong>: Fixed numerous incorrect usages of the term &#8220;dereference&#8221;. Thanks to <a href="#comment-222992">Ranjit</a> for the explanation.</li>
</ul>
<h3>References</h3>
<ol class="note less">
<li><a href="http://download.oracle.com/javase/6/docs/api/java/lang/ref/package-summary.html">Package java.lang.ref</a></li>
<li><a href="http://download.oracle.com/javase/6/docs/api/java/util/WeakHashMap.html">WeakHashMap</a></li>
<li><a href="http://weblogs.java.net/blog/2006/05/04/understanding-weak-references">Understanding Weak References</a></li>
</ol>
<hr/>Copyright &copy; 2012 <strong><a href="http://unitstep.net">unitstep.net</a></strong>. This Feed is for personal non-commercial use only. If you are not reading this material in your news aggregator, the site you are looking at is guilty of copyright infringement. Please contact <strong><a href="mailto:webmaster@unitstep.net">webmaster@unitstep.net</a></strong> for more information.<br/><span style="float: right;font-size: 7pt"><a href="http://blog.taragana.com/index.php/archive/wordpress-plugins-provided-by-taraganacom/">Plugin</a> by <a href="http://www.taragana.com/">Taragana</a></span><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/unitstep?a=0bc-Nt2yHp8:ccCvaQOga-0:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/unitstep?i=0bc-Nt2yHp8:ccCvaQOga-0:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=0bc-Nt2yHp8:ccCvaQOga-0:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/unitstep?i=0bc-Nt2yHp8:ccCvaQOga-0:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=0bc-Nt2yHp8:ccCvaQOga-0:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/unitstep?i=0bc-Nt2yHp8:ccCvaQOga-0:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=0bc-Nt2yHp8:ccCvaQOga-0:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/unitstep?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=0bc-Nt2yHp8:ccCvaQOga-0:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/unitstep?d=yIl2AUoC8zA" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/unitstep/~4/0bc-Nt2yHp8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://unitstep.net/blog/2011/03/26/java-weak-references-and-weakhashmap/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://unitstep.net/blog/2011/03/26/java-weak-references-and-weakhashmap/</feedburner:origLink></item>
		<item>
		<title>Folding changesets with the Mercurial Queues extension</title>
		<link>http://feedproxy.google.com/~r/unitstep/~3/VaU03HwCCNg/</link>
		<comments>http://unitstep.net/blog/2011/01/26/folding-changesets-with-the-mercurial-queues-extension/#comments</comments>
		<pubDate>Thu, 27 Jan 2011 00:59:55 +0000</pubDate>
		<dc:creator>Peter Chng</dc:creator>
				<category><![CDATA[development]]></category>
		<category><![CDATA[mercurial]]></category>
		<category><![CDATA[tutorials]]></category>
		<category><![CDATA[changeset]]></category>
		<category><![CDATA[folding]]></category>
		<category><![CDATA[hg]]></category>
		<category><![CDATA[queues]]></category>

		<guid isPermaLink="false">http://unitstep.net/?p=1215</guid>
		<description><![CDATA[Mercurial is my distributed revision control system of choice, a trait I picked up at my previous job. I haven&#8217;t had the opportunity to deal with Git for any period of time, so I can&#8217;t comment on the various &#8220;Why X is better than Y&#8221; arguments out there. Most of you using Mercurial/Hg (or revision [...]]]></description>
			<content:encoded><![CDATA[<p class="image align-right"><img src="http://unitstep.net/wordpress/wp-content/uploads/2011/01/mercurial-logo.png" alt="" title="mercurial-logo" width="100" height="120" class="alignnone size-full wp-image-1231" /></p>
<p>Mercurial is my distributed revision control system of choice, a trait I picked up at my previous job.  I haven&#8217;t had the opportunity to deal with Git for any period of time, so I can&#8217;t comment on the various &#8220;<a href="http://whygitisbetterthanx.com/">Why X is better than Y</a>&#8221; <a href="http://stevelosh.com/blog/2010/01/the-real-difference-between-mercurial-and-git/">arguments</a> <a href="http://code.google.com/p/support/wiki/DVCSAnalysis">out there</a>. </p>
<p>Most of you using Mercurial/Hg (or revision control in general) will be familiar with the concept of <em>merging</em>, where the changes in a source branch are merged into a target branch, creating a new revision or changeset on the target branch.  But what about the times when you would like to combine two or more changesets/revisions into a single one that has the combined/overall changes of all of them? In that case, the Mercurial Queues extension provides for the concept of <em>folding</em>, which accomplishes just that.</p>
<h2>Mercurial Queues</h2>
<p>The <a href="http://mercurial.selenic.com/wiki/MqExtension">Mercurial Queues extension</a> (<strong>mq</strong>) is one of the most useful Hg extensions available, as it allows for <a href="http://hgbook.red-bean.com/read/mercurial-queues-reference.html">much more</a> than folding.  Basically, mq allows you to import changesets to a <em>patch queue</em>, where they can be manipulated.  In this way, previously immutable changesets can be modified.  One such modification is the concept of <em>folding</em>, where one more more changesets are combined to produce a single changeset with the equivalent effect.</p>
<h2>Proceed with caution</h2>
<p>Because mq can directly modify changesets (i.e. revision history), it can have adverse on your Hg repository; data can be permanently lost, since the changes that can be made cannot be &#8220;backed out&#8221; or &#8220;reverted&#8221;.  <strong>I strongly recommend cloning your Hg repo before undertaking any actions with Mercurial Queues for the first time</strong>, if only for peace of mind and the fact that cloning is such an easy operation with Mercurial.</p>
<h2>The case for folding</h2>
<p>Generally, it&#8217;s not a good idea to go and change revision history, which is what folding does. The purpose of revision control is to <em>preserve</em> history and provide a timeline for how the codebase has evolved.  In the case of Mercurial, it&#8217;s especially troublesome to go and modify revision history on a central server that others are pushing to/pulling from, as this may cause inconsistencies.  Having said that, there are times when combining multiple changesets into one may be beneficial.</p>
<p>Some examples that come to mind are:</p>
<ul class="note">
<li>You have made many intermediate commits to your local Hg repository during development, but would like to combine them into a single one before pushing to a remote/central repository for clarity. (The multiple local commits were for your own sake)</li>
<li>You accidentally committed some sensitive data (i.e. hard-coded passwords) to a repository, followed by some other changes that also removed that sensitive data.  You don&#8217;t want to strip the intermediate (password-containing) revision because of the subsequent work. You can combine the two to one revision that contains the subsequent work but no record of the sensitive data.</li>
</ul>
<p>Folding will help in both situations.</p>
<h2>Tutorial</h2>
<p>This tutorial will cover folding using <a href="http://tortoisehg.org/">TortoiseHg</a>, the popular GUI front-end for Mercurial. Before getting started, you&#8217;ll have to ensure that you don&#8217;t have any uncommitted changes, as you won&#8217;t be able to accomplish some of the steps with outstanding changes. </p>
<p>Open up the Repository Explorer. Below, you can see the example one, with our initial commit, which contained the sensitive data, followed by another that removed it. We&#8217;ll merge them into one.</p>
<p class="image">
<a href="http://unitstep.net/wordpress/wp-content/uploads/2011/01/1.png"><img src="http://unitstep.net/wordpress/wp-content/uploads/2011/01/1-300x138.png" alt="" title="1" width="300" height="138" class="alignnone size-medium wp-image-1247" /></a>
</p>
<p>Next, you&#8217;ll need to enable the Mercurial Queues extension, either through the TortoiseHg UI or by manually editing your <code>mercurial.ini</code> file or per-repo setting file. (<code>.hgrc</code>) Below, I&#8217;ve shown it in the UI: <strong>You need to check off the &#8220;mq&#8221; box under &#8220;Extensions&#8221;</strong>.</p>
<p class="image">
<a href="http://unitstep.net/wordpress/wp-content/uploads/2011/01/2.png"><img src="http://unitstep.net/wordpress/wp-content/uploads/2011/01/2-286x300.png" alt="" title="2" width="286" height="300" class="alignnone size-medium wp-image-1248" /></a>
</p>
<p>You&#8217;ll need to close the Repository Explorer and re-open it for the mq extension to take effect in the UI. </p>
<p>Next, select the <strong>oldest</strong> changeset and then <strong>right-click the newest one</strong>; in the context menu, select &#8220;Import from here to selected MQ&#8221;.</p>
<p class="image">
<a href="http://unitstep.net/wordpress/wp-content/uploads/2011/01/3.png"><img src="http://unitstep.net/wordpress/wp-content/uploads/2011/01/3-300x147.png" alt="" title="3" width="300" height="147" class="alignnone size-medium wp-image-1249" /></a>
</p>
<p>Then, open the Patch Queue by clicking its icon or selecting <strong>View > Patch Queue</strong> from the menu.</p>
<p class="image">
<a href="http://unitstep.net/wordpress/wp-content/uploads/2011/01/4.png"><img src="http://unitstep.net/wordpress/wp-content/uploads/2011/01/4-300x147.png" alt="" title="4" width="300" height="147" class="alignnone size-medium wp-image-1250" /></a>
</p>
<p>You should be able to see the changesets in your patch queue on the left side drawer.  They&#8217;ll be labeled 0.diff, 1.diff, etc. You can also see which patch corresponds to which changeset because the imported changesets will have be labeled in the UI with <strong>qbase, qtip, 0.diff, 1.diff</strong>, etc. (They are listed in the patch queue in opposite order)</p>
<p class="image">
<a href="http://unitstep.net/wordpress/wp-content/uploads/2011/01/5.png"><img src="http://unitstep.net/wordpress/wp-content/uploads/2011/01/5-300x106.png" alt="" title="5" width="300" height="106" class="alignnone size-medium wp-image-1251" /></a>
</p>
<p>Now, right-click the <strong>top/oldest one</strong> in the patch queue, and select &#8220;Goto&#8221;. This will bring you back to the oldest changeset and <strong>remove</strong> the previous ones from your repository.  But don&#8217;t worry, the changesets still exist in your (mercurial) queue.</p>
<p class="image">
<a href="http://unitstep.net/wordpress/wp-content/uploads/2011/01/6.png"><img src="http://unitstep.net/wordpress/wp-content/uploads/2011/01/6-300x115.png" alt="" title="6" width="300" height="115" class="alignnone size-medium wp-image-1252" /></a>
</p>
<p>Now, right click the next oldest one (which was removed from your repository), click &#8220;Fold&#8221; and then &#8220;Yes&#8221;.  This will effectively fold or combine the two changesets into a single one with the equivalent changes/effects.  <strong>Please note that this operation cannot be reversed</strong>, so make sure you really want to do it. (You did clone/backup your repository before starting, right?)</p>
<p class="image">
<a href="http://unitstep.net/wordpress/wp-content/uploads/2011/01/7.png"><img src="http://unitstep.net/wordpress/wp-content/uploads/2011/01/7-300x138.png" alt="" title="7" width="300" height="138" class="alignnone size-medium wp-image-1253" /></a>
</p>
<p class="image">
<a href="http://unitstep.net/wordpress/wp-content/uploads/2011/01/8.png"><img src="http://unitstep.net/wordpress/wp-content/uploads/2011/01/8.png" alt="" title="8" width="256" height="155" class="alignnone size-full wp-image-1254" /></a>
</p>
<p>You can now adjust the commit comment/message and username, if you like, by clicking &#8220;Commit&#8221; or by selecting <strong>Tools > Commit</strong> from the menu. You may need to select <strong>View > Advanced</strong> to change/show the username.  By default the commit message of the folded/unified changeset is an aggregate of the changesets that were combined to form it. You&#8217;ll probably want to adjust this down to something more meaningful. </p>
<p>After you are done, be sure to click <strong>&#8220;QRefresh&#8221;</strong> before closing the window.</p>
<p class="image">
<a href="http://unitstep.net/wordpress/wp-content/uploads/2011/01/9.png"><img src="http://unitstep.net/wordpress/wp-content/uploads/2011/01/9-300x103.png" alt="" title="9" width="300" height="103" class="alignnone size-medium wp-image-1255" /></a>
</p>
<p>After you&#8217;ve done the folding and modifying the commit message, you can right click the patch file (0.diff in this case) and select &#8220;Finish Applied&#8221; to put the folded/unified changeset back into your repository.</p>
<p class="image">
<a href="http://unitstep.net/wordpress/wp-content/uploads/2011/01/10.png"><img src="http://unitstep.net/wordpress/wp-content/uploads/2011/01/10-300x122.png" alt="" title="10" width="300" height="122" class="alignnone size-medium wp-image-1256" /></a>
</p>
<p>Your MQ patch queue should now be <strong>empty</strong> and the repository browser should show only one changeset, with your updated comments and no MQ tags/labels on the changeset. You can close the patch queue sidebar now, if you&#8217;d like.</p>
<p class="image">
<a href="http://unitstep.net/wordpress/wp-content/uploads/2011/01/11.png"><img src="http://unitstep.net/wordpress/wp-content/uploads/2011/01/11-300x156.png" alt="" title="11" width="300" height="156" class="alignnone size-medium wp-image-1257" /></a>
</p>
<p>There! Now all evidence of your nefarious activities has now been removed. Only the beginning and the end remain. Use wisely.</p>
<hr/>Copyright &copy; 2012 <strong><a href="http://unitstep.net">unitstep.net</a></strong>. This Feed is for personal non-commercial use only. If you are not reading this material in your news aggregator, the site you are looking at is guilty of copyright infringement. Please contact <strong><a href="mailto:webmaster@unitstep.net">webmaster@unitstep.net</a></strong> for more information.<br/><span style="float: right;font-size: 7pt"><a href="http://blog.taragana.com/index.php/archive/wordpress-plugins-provided-by-taraganacom/">Plugin</a> by <a href="http://www.taragana.com/">Taragana</a></span><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/unitstep?a=VaU03HwCCNg:SUwGP6cjW1U:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/unitstep?i=VaU03HwCCNg:SUwGP6cjW1U:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=VaU03HwCCNg:SUwGP6cjW1U:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/unitstep?i=VaU03HwCCNg:SUwGP6cjW1U:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=VaU03HwCCNg:SUwGP6cjW1U:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/unitstep?i=VaU03HwCCNg:SUwGP6cjW1U:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=VaU03HwCCNg:SUwGP6cjW1U:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/unitstep?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=VaU03HwCCNg:SUwGP6cjW1U:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/unitstep?d=yIl2AUoC8zA" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/unitstep/~4/VaU03HwCCNg" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://unitstep.net/blog/2011/01/26/folding-changesets-with-the-mercurial-queues-extension/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://unitstep.net/blog/2011/01/26/folding-changesets-with-the-mercurial-queues-extension/</feedburner:origLink></item>
		<item>
		<title>What I’ve been up to</title>
		<link>http://feedproxy.google.com/~r/unitstep/~3/HjXiA_Q3ljg/</link>
		<comments>http://unitstep.net/blog/2011/01/16/what-ive-been-up-to/#comments</comments>
		<pubDate>Sun, 16 Jan 2011 19:46:09 +0000</pubDate>
		<dc:creator>Peter Chng</dc:creator>
				<category><![CDATA[asides]]></category>
		<category><![CDATA[Life]]></category>

		<guid isPermaLink="false">http://unitstep.net/?p=1194</guid>
		<description><![CDATA[I&#8217;ve had a serious lapse in updating this blog with useful information, and for that I apologize. I would have liked to continue to provide helpful guides and other tutorials, but I continually found excuses to be lazy. Writing these guides is as helpful for readers as it is for me, so it&#8217;s something that [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve had a serious lapse in updating this blog with useful information, and for that I apologize.  I would have liked to continue to provide helpful <a href="/blog/category/guides/">guides</a> and other <a href="/blog/category/tutorials/">tutorials</a>, but I continually found excuses to be lazy.  Writing these guides is as helpful for readers as it is for me, so it&#8217;s something that I need to engage in more often if I am to continue with personal development.</p>
<p>With that in mind, I thought it&#8217;d be useful to provide an update on what I&#8217;ve been up to for the past few months, to keep things in perspective.</p>
<h2>Changing roles</h2>
<p>During the summer, I started a new job. As with any new job, there is an adjustment period and during that time I wanted to stay focused on getting up to speed and being able to deliver in the role I was hired for.  I&#8217;m always apprehensive about new environments, so I wanted to take the time to properly learn the ropes and not be too assertive, while at the same time not being too withdrawn.</p>
<p>I&#8217;m glad to report that things are going quite well.  The new position suits me well, and most importantly, the people there are great to work with.  My new team lead, and indeed many of my other team members have also been recently hired, so I was a little less intimidated as I was by no means the only &#8220;new guy&#8221;. Since then, we have all had to opportunity to learn, grow and adjust to the environment, so it&#8217;s been a great team-building exercise of sorts. (As you can tell, the company is very much in a growth phase at this point)</p>
<p>About the only thing I don&#8217;t like is having to drive to work, as the new workplace is out is Mississauga.  It&#8217;s not a horrible commute (~30 minutes one-way), but it&#8217;s just that I don&#8217;t like driving. </p>
<h2>Boston 2011 Training</h2>
<p>The other big event in my life has been <a href="/blog/2010/10/09/qualified-for-the-boston-marathon/">qualifying for the Boston Marathon</a>, which I did last year in <a href="http://torontowaterfrontmarathon.com/en/index.htm">STWM 2010</a>.</p>
<p>Luckily, I managed to get in the day registration opened, as all the spots for the <a href="http://rwdaily.runnersworld.com/2010/10/boston-is-closed.html">2011 Boston Marathon filled within 8 hours</a>! The fast fill-up time can probably be attributed to a self-fulfilling prophesy, as the people who were locked out last year (when registration filled in &#8220;only&#8221; 2 months) vowed not to miss it again. This created rumours that things would fill up even faster, and likely created a &#8220;bank run&#8221; type scenario. </p>
<p>I quickly booked my hotel and flight down to Beantown for April this year, as I didn&#8217;t want to miss out because of something logistical.  But my planning for Boston hasn&#8217;t been limited to administrative items though, as there is of course the training required.</p>
<p>For this next marathon, which will be my sixth, I decided that I need a new approach, one that involved following a proper training plan.  Before this, my training had always been self-developed &#8211; that is, lacking structure and reason. I would basically run four times a week: One long run on the weekend, followed by three ~10 km runs during the week.  All of these would be run at the fastest pace that I could sustain over the distance.</p>
<p>This seemed to work, at least for a while, as I managed at 3:02:50 performance in the 2009 Edmonton marathon.  However, this was followed by a disastrous 3:27 finish in the 2009 Toronto GoodLife marathon, and a qualifying near-miss in the 2010 Mississauga marathon where I finished in 3:13.  Having just barely qualified during the 2010 STWM with a time of 3:10:46 (and that was only due to sheer willpower during the last 2.2 km), I knew a different approach was required, one that was more regimented.</p>
<h2>A new approach to training</h2>
<p>So I bought a few books and began reading up online about exercise physiology.  I quickly learned that I had simply been running all my training runs <em>too fast</em>, which seems contradictory to the goals of training. After all, to run a race fast, shouldn&#8217;t you train fast? It turns out, the truth is not so simple.</p>
<p>Basically, by running everything as fast as I could during training, I wasn&#8217;t giving my body time to properly recover.  Strictly speaking, it isn&#8217;t the workout that improves your fitness &#8211; as after a workout, you are tired and your performance is actually decreased.  It&#8217;s actually the <em>supercompensation</em> that happens during the recovery phase that improves your fitness.  Without recovery, hard training will simply break down your body and leave you less capable.</p>
<p>That&#8217;s what was happening to me &#8211; I was &#8220;leaving my best race on the track&#8221;, as famed distance running coach <a href="http://www.amazon.com/Daniels-Running-Formula-2nd-Jack/dp/0736054928">Daniels</a> would say.  With all that hard running, each workout began to seem tougher and tougher &#8211; though the actual intensity was not getting harder.  Soon, it got to the point where I could not complete my four runs per week, and had to switch to cross-training in a vain attempt to preserve my fitness. It turns out, this is a common pitfall of amateur runners as they attempt to devise their own &#8220;training plan.&#8221;</p>
<h2>Rest and recovery</h2>
<p>After all of this, I needed a recovery period. I took some downtime after my fall marathon, and when to physiotherapy for some issues I was having with my right knee.  It turns out I had PFPS (Patello femoral pain syndrome), which is basically a kneecap-tracking problem caused by muscle imbalances and likely aggravated by all the hard running I was doing.  I was given some exercises to do and also began some strength training for my quads, and during the past three months the pain progressively decreased and is now almost completely gone. During this time, I was never prevented from running.</p>
<p>But I also began to change how I ran. I no longer ran everything at the fastest pace possible.  In fact, for two months, I reverted to a &#8220;base training&#8221; phase, where all my runs were done at < 70% HRR (Heart Rate Reserve). At first, it was painful to run this slow. But I stuck to the ideas that <a href="http://www.markallenonline.com/maoArticles.aspx?AID=4">others had proven</a> effective, and I was able to increase my weekly distance up to levels I&#8217;d never touched before, all while remaining injury free.  </p>
<p>During this time, I also worked on shortening my stride and increasing my cadence, thus moving away from a heel-striking gait to more of a midfoot strike.  I believe this has prevented my plantar fasciitis from returning, something I struggled with for over a year.  At the end of this phase, I did a time trial on the treadmill, and I was no slower at 10 km than before.  In fact, physically, I felt much more stronger and refreshed.</p>
<h2>Marathon training</h2>
<p>With recovery out of the way, the question of which training plan to follow came up.  After consulting with the folks over at the <a href="http://www.runnersworld.com/community/forums/races-places/boston-marathon">RWOL Boston forums</a>, it became clear that many of them were following the plan from <a href="http://www.amazon.com/Advanced-Marathoning-2nd-Peter-Pfitzinger/dp/0736074600">Advanced Marathoning</a>, by Pete Pfitzinger.  Pftizinger and Daniels have very similar ideas &#8211; specific runs at specific paces to train different parts of your physiology necessary for the marathon &#8211; but Pfitzinger is a more specific with his training schedule, something I desired.</p>
<p>At first, things were a bit daunting &#8211; after all, the lowest-mileage plan (which I planned on following) has a maximum week of 88 km, something I&#8217;ve never done before.  But the beauty of the plans is that while there&#8217;s a lot of mileage, there&#8217;s a selective use of hard running.  Pfitz always places sufficient time between hard runs, filling them with slower-paced runs that keep your cardiovascular system in shape while allowing your legs to recover from the harder efforts. It&#8217;s a much more sane approach.</p>
<p>I&#8217;m following the 18-week plan that peaks at 88 km, (commonly referred to as &#8220;18/55&#8243; since 55 miles is about 88 km) and have just finished the 5th week. I feel great &#8211; a lot stronger and most importantly, remain injury free.  Hopefully things will remain that way.</p>
<h2>Summing it up</h2>
<p>Besides updates on my marathon training progress, I will aim to add a few more development/programming related guides.  I have the beginnings of a few, but just need the motivation to put them together. Hopefully that will not be interrupted by laziness.  But <a href="http://www.quotationspage.com/quote/571.html">Lennon once said</a>, <em>&#8220;Life is what happens to you while you&#8217;re busy making other plans.&#8221;</em>.</p>
<hr/>Copyright &copy; 2012 <strong><a href="http://unitstep.net">unitstep.net</a></strong>. This Feed is for personal non-commercial use only. If you are not reading this material in your news aggregator, the site you are looking at is guilty of copyright infringement. Please contact <strong><a href="mailto:webmaster@unitstep.net">webmaster@unitstep.net</a></strong> for more information.<br/><span style="float: right;font-size: 7pt"><a href="http://blog.taragana.com/index.php/archive/wordpress-plugins-provided-by-taraganacom/">Plugin</a> by <a href="http://www.taragana.com/">Taragana</a></span><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/unitstep?a=HjXiA_Q3ljg:DHH51E6oub4:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/unitstep?i=HjXiA_Q3ljg:DHH51E6oub4:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=HjXiA_Q3ljg:DHH51E6oub4:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/unitstep?i=HjXiA_Q3ljg:DHH51E6oub4:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=HjXiA_Q3ljg:DHH51E6oub4:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/unitstep?i=HjXiA_Q3ljg:DHH51E6oub4:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=HjXiA_Q3ljg:DHH51E6oub4:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/unitstep?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/unitstep?a=HjXiA_Q3ljg:DHH51E6oub4:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/unitstep?d=yIl2AUoC8zA" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/unitstep/~4/HjXiA_Q3ljg" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://unitstep.net/blog/2011/01/16/what-ive-been-up-to/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://unitstep.net/blog/2011/01/16/what-ive-been-up-to/</feedburner:origLink></item>
	</channel>
</rss>

