<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3705947190453566253</id><updated>2024-10-27T06:12:30.274+08:00</updated><category term="Java"/><category term="Sorting"/><category term="unix"/><category term="Groovy"/><category term="python"/><category term="testing"/><category term="Directed Graphs"/><category term="Graphs"/><category term="Teamcity"/><category term="junit"/><category term="Ant"/><category term="Availability"/><category term="Bitwise Operator"/><category term="Breadth First Search"/><category term="Bubble Sort"/><category term="Build Management"/><category term="Builder Pattern"/><category term="Continuous Integration"/><category term="Depth First Search"/><category term="Farmer Wolf Goat"/><category term="Fibonacci"/><category term="Insertion Sort"/><category term="Merge Sort"/><category term="Object Modelling"/><category term="Riddle"/><category term="Scalability"/><category term="Selection Sort"/><category term="Software Development"/><category term="Stack"/><category term="State Space Graph"/><category term="Topological Sort"/><category term="bash"/><category term="benchmark"/><category term="caliper"/><category term="find"/><category term="packing"/><category term="performance"/><category term="python vs java"/><category term="redirection"/><category term="sed"/><category term="unix cheat sheet"/><category term="unpacking"/><title type='text'>Yong Ouyang</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://yongouyang.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://yongouyang.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Yong Ouyang</name><uri>http://www.blogger.com/profile/05612250828808301428</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>21</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3705947190453566253.post-5175034396301313466</id><published>2013-06-18T21:41:00.000+08:00</published><updated>2013-06-18T21:41:26.568+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Build Management"/><category scheme="http://www.blogger.com/atom/ns#" term="Continuous Integration"/><category scheme="http://www.blogger.com/atom/ns#" term="Teamcity"/><title type='text'>Use Teamcity as the Continuous Integration and Build Management Server</title><content type='html'>I&#39;ve been using Teamcity as the continuous integration and build management server for the last few years. Not until recently I tried out Hudson (or Jenkins) as the alternative solution. It is quite frustrated to learn that Hudson, being an open-sourced project, doesn&#39;t even support remote build (where I can submit my local changes to Teamcity and run a selected builds, and commit once all the builds are successful).&lt;br /&gt;
&lt;br /&gt;
In the scenario where the project has quite a number of builds for various tests, e.g. unit tests, integration tests, external tests, smoke tests, etc., running these tests with my local changes to check whether I break any existing tests or not is rather crucial in agile development approach, where I always want to have a feedback in the shortest amount of time. Of course, without being able to do a remote run with multiple test suites running in parallel, you may argue that I can still run the test suites locally one by one, and only check in when all the tests pass locally, in which case, Hudson is sufficient enough and it is FREE!&lt;br /&gt;
&lt;br /&gt;
I don&#39;t intend to devote my blog to compare Teamcity and Hudson, but given the experiences of using both, I can conclude that Teamcity is no doubt the first choice in terms of CI and build management, as its feature is a perfect match for a developer with TDD (Test-Driven Development) and agile mind set. Having said that, I am gonna demonstrate how easy it is to setup the Teamcity for my project hosted on Git. JetBrains does offer a Teamcity professional version which is FREE and comes with a limit of 20 build configurations and 3 build agents. &lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;Installation&lt;/h2&gt;&lt;li&gt;&lt;a href=&quot;http://www.jetbrains.com/teamcity/download/&quot;&gt;Download&lt;/a&gt; the latest version for Linux (or whichever suits your OS)&lt;/li&gt;&lt;br /&gt;
&lt;li&gt;Unzip the downloaded file, e.g. tar -zxvf TeamCity-7.1.5.tar.gz&lt;br /&gt;
&lt;pre&gt;youyang@monkey-dev-01:/app&amp;gt; ll
total 12
drwxr-xr-x  6 youyang users 4096 Mar 22 02:31 monkey
drwxr-xr-x 12 youyang users 4096 Jun 14 09:31 TeamCity
drwxr-xr-x 13 youyang users 4096 Jun 15 09:11 TeamCity-BuildAgent
youyang@monkey-dev-01:/app&amp;gt; 
&lt;/pre&gt;&lt;/li&gt;&lt;br /&gt;
&lt;li&gt;start up teamcity, e.g. ./app/TeamCity/bin/startup.sh , on port 8111 by default&lt;/li&gt;&lt;br /&gt;
&lt;a href=&quot;http://www.blogger.com/blogger.g?blogID=3705947190453566253&amp;amp;pli=1&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;h2&gt;Configuration&lt;/h2&gt;&lt;li&gt;browse to http://localhost:8111 to verify that Teamcity has started up successfully, which will take a minute or two before it asks you to setup an admin account&lt;/li&gt;&lt;br /&gt;
&lt;li&gt;once the admin account is created and logged in, go to the Administration menu to create a new Project. Specify name and description on the General tab, shown as below&lt;/li&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://www.blogger.com/blogger.g?blogID=3705947190453566253&amp;amp;pli=1&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhpGJJ9iKT5zHu409OxSlHW7RvDHUbMVqt9U5TUQq6oaH6LAuQFuIa6L3SW5ST-jFEllVz1nFfZWY2BL15CGXMSESYDjZVOyc-6nqigv9ALHp2DyoEj2VSyElkUPP8b-WQtSIcjsQemZDO/s1600/New_Project.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhpGJJ9iKT5zHu409OxSlHW7RvDHUbMVqt9U5TUQq6oaH6LAuQFuIa6L3SW5ST-jFEllVz1nFfZWY2BL15CGXMSESYDjZVOyc-6nqigv9ALHp2DyoEj2VSyElkUPP8b-WQtSIcjsQemZDO/s1600/New_Project.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;li&gt;create a new VCS root on the VCS Roots tab, and choose Git (or whatever VCS you use), then fill in the information as shown below&lt;/li&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSxtgbXK9eBGmLRFiPQ31sNQUHzJenb5pAHPP_bLmN-jHQ6CjFBpUqRzvkfft15qjXeMGugWtus705RsrsQh-8SEPcJyPigO7bNwnx2_AqWpEuQts_Lk7Q4X96DgAmHFq-pXuC_GiGDjbW/s1600/New_Git.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSxtgbXK9eBGmLRFiPQ31sNQUHzJenb5pAHPP_bLmN-jHQ6CjFBpUqRzvkfft15qjXeMGugWtus705RsrsQh-8SEPcJyPigO7bNwnx2_AqWpEuQts_Lk7Q4X96DgAmHFq-pXuC_GiGDjbW/s1600/New_Git.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;li&gt;go back to the project config, and create a build configuration&lt;/li&gt;&lt;br /&gt;
&lt;li&gt;complete a minimum 3-step configuration for the build. Fill in the build name and description for Step 1; Choose the VCS root specified before in Step 2; Specify the build step with Ant (or other build runners the project is using), as shown below&lt;/li&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAYUnSA_6m8_XNmKervbL49LYUfDnhyphenhyphenL0UcxB6NExtPnuPR4KcKaah8m6afGnDDe9AThpKRBVIw60sSo5skJWuuYR3DN5EOHaRVbFkFrT73CaIxkG2oOj1a3B5tO5AQurnJqrCZuhpvctl/s1600/Build_Step.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAYUnSA_6m8_XNmKervbL49LYUfDnhyphenhyphenL0UcxB6NExtPnuPR4KcKaah8m6afGnDDe9AThpKRBVIw60sSo5skJWuuYR3DN5EOHaRVbFkFrT73CaIxkG2oOj1a3B5tO5AQurnJqrCZuhpvctl/s1600/Build_Step.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;li&gt;this is the minimum configuration for a project with only one build configuration, which is good enough for the demo&lt;/li&gt;&lt;br /&gt;
&lt;h2&gt;Teamcity Agent&lt;/h2&gt;&lt;li&gt;With a project setup on Teamcity server, we still need to install agents so that we can run the builds on them. Go Administration-&gt;Install Build Agents, notice that the link for the zip file distribution is http://monkey-dev-01:8111/update/buildAgent.zip&lt;/li&gt;&lt;br /&gt;
&lt;li&gt;On the machine that you want to install your build agent, wget the zip file from, e.g. http://monkey-dev-01:8111/update/buildAgent.zip, unzip to, e.g. /app/TeamCity-BuildAgent folder&lt;/li&gt;&lt;br /&gt;
&lt;li&gt;create the buildAgent.properties from the template file buildAgent.dist.properties under, e.g. /app/TeamCity-BuildAgent/conf folder&lt;/li&gt;&lt;br /&gt;
&lt;li&gt;setup the following properties in the buildAgent.properties file&lt;/li&gt;&lt;br /&gt;
&lt;pre&gt;# name of the agent appearing on Teamcity server
name=Monkey-Dev-01
# setup the JDK
env.JAVA_HOME=/app/monkey/java
&lt;/pre&gt;&lt;li&gt;start up the agent in the background by typing &quot;/app/TeamCity-BuildAgent/bin/agent.sh start&quot;&lt;/li&gt;&lt;br /&gt;
&lt;li&gt;Wait a few minutes before your agent shown under the Agents-&gt;Connected tab on Teamcity server, as shown below&lt;/li&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqQCAPvJuFxVb8xbfGinhJLM1YLeSKampFcFge2PLQgi_MlNwijCo3rEDRxYEZR0DO-yG8Z3Q-zm3gC1CjIVxNlNWwrTiVypd_TxkA7obwcg7pzu0vdLiOBJ6WIQYDIdVxsSnpoEyyu6vy/s1600/Agent.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqQCAPvJuFxVb8xbfGinhJLM1YLeSKampFcFge2PLQgi_MlNwijCo3rEDRxYEZR0DO-yG8Z3Q-zm3gC1CjIVxNlNWwrTiVypd_TxkA7obwcg7pzu0vdLiOBJ6WIQYDIdVxsSnpoEyyu6vy/s1600/Agent.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;li&gt;Once the agent is connected, you are ready to run your first build on Teamcity:&lt;/li&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGbsq_YQI0mNqvuwmQdhoHP9XrHlQxAuZOFksoZ1N9P4tcGxdcAT-rg-j1O_YCeNyPFhnXdEtKMG6zQ7We_rZda_Mppx0oSvEXrE97vhffMpg1o20L1GhhmtGnGhTYQO7_YQUL6BV6r2BB/s1600/overview.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGbsq_YQI0mNqvuwmQdhoHP9XrHlQxAuZOFksoZ1N9P4tcGxdcAT-rg-j1O_YCeNyPFhnXdEtKMG6zQ7We_rZda_Mppx0oSvEXrE97vhffMpg1o20L1GhhmtGnGhTYQO7_YQUL6BV6r2BB/s1600/overview.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;li&gt;If you are using Intellij IDE, install the Teamcity plugin so that you can send a remote run to the Teamcity server by selecting which builds to run.&lt;/li&gt;&lt;br /&gt;
&lt;br /&gt;
</content><link rel='replies' type='application/atom+xml' href='http://yongouyang.blogspot.com/feeds/5175034396301313466/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://yongouyang.blogspot.com/2013/06/use-teamcity-as-continuous-integration.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/5175034396301313466'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/5175034396301313466'/><link rel='alternate' type='text/html' href='http://yongouyang.blogspot.com/2013/06/use-teamcity-as-continuous-integration.html' title='Use Teamcity as the Continuous Integration and Build Management Server'/><author><name>Yong Ouyang</name><uri>http://www.blogger.com/profile/05612250828808301428</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhpGJJ9iKT5zHu409OxSlHW7RvDHUbMVqt9U5TUQq6oaH6LAuQFuIa6L3SW5ST-jFEllVz1nFfZWY2BL15CGXMSESYDjZVOyc-6nqigv9ALHp2DyoEj2VSyElkUPP8b-WQtSIcjsQemZDO/s72-c/New_Project.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3705947190453566253.post-6877384760979030514</id><published>2013-05-10T12:31:00.000+08:00</published><updated>2013-05-10T12:31:21.445+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Bitwise Operator"/><category scheme="http://www.blogger.com/atom/ns#" term="Java"/><category scheme="http://www.blogger.com/atom/ns#" term="packing"/><category scheme="http://www.blogger.com/atom/ns#" term="unpacking"/><title type='text'>Bitwise Operations in Java</title><content type='html'>The bitwise operations in Java are rarely discussed, and you can sense that by reading the &lt;a href=&quot;http://docs.oracle.com/javase/tutorial/java/nutsandbolts/op3.html&quot;&gt;official tutorials&lt;/a&gt; on this topic. However, there are interesting usages that you should probably be aware of.&lt;br /&gt;
&lt;br /&gt;
The bitwise operators operates on integral types (int and long). Before explaining how bitwise operators work, you should have an idea of how integers are represented in the binary form. As mentioned by the official &lt;a href=&quot;http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html&quot;&gt;primitive data type&lt;/a&gt; tutorials, the &lt;b&gt;int&lt;/b&gt; data type is a 32-bit signed 2&#39;s complement integer, whose value ranges from -2^32 to 2^32-1, inclusively. On the other hand, the &lt;b&gt;long &lt;/b&gt;data type is a 64-bit signed 2&#39;s complement integer, whose value ranges from -2^64 to 2^64-1, inclusively. In both cases, the highest order bit of &lt;b&gt;int &lt;/b&gt;and &lt;b&gt;long&lt;/b&gt; shows the sign of the value and is not part of the numeric value, where 0 being positive and 1 being negative.&lt;br /&gt;
&lt;br /&gt;
For example, an int value of 1 in binary form looks like this&lt;br /&gt;
&lt;pre&gt;00000000000000000000000000000001
&lt;/pre&gt;while an int value of -1 in binary form looks like this&lt;br /&gt;
&lt;pre&gt;11111111111111111111111111111111
&lt;/pre&gt;The negative value is transformed in 2 steps:&lt;br /&gt;
&lt;pre&gt;Step 1: bitwise complement of +1, such that
00000000000000000000000000000001 
becomes
11111111111111111111111111111110

Step 2: add 1, such that
11111111111111111111111111111110 
becomes
11111111111111111111111111111111
&lt;/pre&gt;Given a negative value, where the highest (leftmost) bit is 1, you can work out what value the binary form represents in 2 steps:&lt;br /&gt;
&lt;pre&gt;Step 1: bitwise complement of the binary value, such that
11111111111111111111111111111011
becomes
00000000000000000000000000000100

Step 2: add 1, such that
00000000000000000000000000000100
becomes
00000000000000000000000000000101
&lt;/pre&gt;Therefore, the original binary form represents -5.&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;The bitwise operators&lt;/h2&gt;&lt;table border=&quot;1&quot; cellpadding=&quot;4&quot; cellspacing=&quot;0&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;th&gt;Operator&lt;/th&gt;&lt;th&gt;Name&lt;/th&gt;&lt;th&gt;Example&lt;/th&gt;&lt;th&gt;Result&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;&lt;i&gt;a&lt;/i&gt; &amp;amp; &lt;i&gt;b&lt;/i&gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;and&lt;/td&gt;&lt;td&gt;6 &amp;amp; 9&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;1 if both bits are 1, or 0 if either bit is 0&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;&lt;i&gt;a&lt;/i&gt; | &lt;i&gt;b&lt;/i&gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;or&lt;/td&gt;     &lt;td&gt;6 | 9&lt;/td&gt;&lt;td&gt;15&lt;/td&gt;&lt;td&gt;1 if either bit is 1, or 0 if both bits are 0&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;&lt;i&gt;a&lt;/i&gt; ^ &lt;i&gt;b&lt;/i&gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;xor&lt;/td&gt;    &lt;td&gt;6 ^ 9&lt;/td&gt;&lt;td&gt;15&lt;/td&gt;&lt;td&gt;1 if both bits are different, 0 if both bits are the same&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;~&lt;i&gt;a&lt;/i&gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;not&lt;/td&gt;              &lt;td&gt;~9       &lt;/td&gt;&lt;td&gt;-10&lt;/td&gt;&lt;td&gt;Inverts the bits. (equivalent to +1 and then change sign)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;&lt;i&gt;n&lt;/i&gt; &amp;lt;&amp;lt; &lt;i&gt;p&lt;/i&gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;left shift&lt;/td&gt;&lt;td&gt;60 &amp;lt;&amp;lt; 2&lt;/td&gt;&lt;td&gt;240&lt;/td&gt;&lt;td&gt;Shifts the bits of &lt;i&gt;n&lt;/i&gt; left &lt;i&gt;p&lt;/i&gt;             positions.  Zero bits are shifted into the low-order positions.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;&lt;i&gt;n&lt;/i&gt; &amp;gt;&amp;gt; &lt;i&gt;p&lt;/i&gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;right shift&lt;/td&gt;&lt;td&gt;60 &amp;gt;&amp;gt; 2&lt;/td&gt;&lt;td&gt;15&lt;/td&gt;&lt;td&gt;Shifts the bits of &lt;i&gt;n&lt;/i&gt; right &lt;i&gt;p&lt;/i&gt;             positions.  If &lt;i&gt;n&lt;/i&gt; is a 2&#39;s complement signed number, the sign bit              is shifted into the high-order positions.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;&lt;i&gt;n&lt;/i&gt; &amp;gt;&amp;gt;&amp;gt; &lt;i&gt;p&lt;/i&gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;unsigned right shift&lt;/td&gt;&lt;td nowrap=&quot;true&quot;&gt;-60 &amp;gt;&amp;gt;&amp;gt; 20&lt;/td&gt;&lt;td&gt;4095&lt;/td&gt;&lt;td&gt;Shifts the bits of &lt;i&gt;n&lt;/i&gt; right &lt;i&gt;p&lt;/i&gt;             positions.  Zeros are shifted into the high-order positions.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;
&lt;h2&gt;Packing and Unpacking&lt;/h2&gt;Multiple int values of limited range can be &quot;packed&quot; into one int, by using the bitwise operators. For example, we have the following integer variables age (range 0~255, or 8-bit), gender (0~1, or 1-bit), weight (range 0~255, or 8-bit), and height (range 0-255, or 8-bit). These integers can be packed and unpacked into/from a 32-bit integer like this:&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/yongouyang/5552286.js&quot;&gt;&lt;/script&gt;&lt;br /&gt;
&lt;h2&gt;Represent boolean values in a byte&lt;/h2&gt;Suppose we have 8 boolean values that are true or false, and we want to store them in a single byte, and sent it across the network, and then unpack it and use it to toggle 8 different things:&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/yongouyang/5552352.js&quot;&gt;&lt;/script&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;Multiply and Divide&lt;/h2&gt;When using x &lt;&lt; 3, it is equivalent to multiply x by 8 (or 2^3); similarly, when using x &gt;&gt; 2, it is equivalent to divide x by 4 (or 2^2). In fact, a smart enough compiler will replace your multiplication or division expressions using bit shift operators such that it is more compact and faster. So there is no need to explicitly use bit shift operator if you want multiply or divide by a power of 2!&lt;br /&gt;
</content><link rel='replies' type='application/atom+xml' href='http://yongouyang.blogspot.com/feeds/6877384760979030514/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://yongouyang.blogspot.com/2013/05/bitwise-operations-in-java.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/6877384760979030514'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/6877384760979030514'/><link rel='alternate' type='text/html' href='http://yongouyang.blogspot.com/2013/05/bitwise-operations-in-java.html' title='Bitwise Operations in Java'/><author><name>Yong Ouyang</name><uri>http://www.blogger.com/profile/05612250828808301428</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3705947190453566253.post-6743663833095859217</id><published>2013-04-18T10:11:00.003+08:00</published><updated>2013-04-18T10:11:28.747+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="bash"/><category scheme="http://www.blogger.com/atom/ns#" term="redirection"/><category scheme="http://www.blogger.com/atom/ns#" term="unix"/><title type='text'>I/O Redirection in Bash</title><content type='html'>Since Bash is a superset of Bourne shell, the IO redirection is the same across the Bourne shell family. To find out exactly which shell you are using in Unix or Linux, typing in command&lt;br /&gt;
&lt;pre&gt;echo $SHELL
&lt;/pre&gt;shall display an executable command with its path, for example&lt;br /&gt;
&lt;table align=&quot;center&quot; border=&quot;1&quot;&gt;&lt;thead&gt;
&lt;tr&gt;&lt;td&gt;Path&lt;/td&gt;&lt;td&gt;Shell&lt;/td&gt;&lt;/tr&gt;
&lt;/thead&gt;  &lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;/bin/sh&lt;/td&gt;&lt;td&gt;Bourne shell&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;/bin/bash&lt;/td&gt;&lt;td&gt;Bourne Again SHell&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;/bin/csh&lt;/td&gt;&lt;td&gt;C SHell&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;/bin/ksh&lt;/td&gt;&lt;td&gt;Korn SHell&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt; &lt;/table&gt;&lt;br /&gt;
Bash takes input from standard input (&lt;b&gt;stdin&lt;/b&gt;), writes output to standard output (&lt;b&gt;stdout&lt;/b&gt;), and writes error output to standard error (&lt;b&gt;stderr&lt;/b&gt;). Standard input is connected to the terminal keyboard, while standard output and error are connected to the terminal screen, by default. Redirection of I/O is accomplished by using a redirection metacharacter followed by the desired destination (stdout &amp;amp; stderr) or source (stdin). Bash uses file descriptor numbers to refer to the standard I/O, where 0 is standard input, 1 is standard output, and 2 is standard error. Below are the common redirection for the Bourne shell family:&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; border=&quot;1&quot;&gt;&lt;thead&gt;
&lt;tr&gt;&lt;td&gt;Meta Character&lt;/td&gt;&lt;td&gt;Action&lt;/td&gt;&lt;/tr&gt;
&lt;/thead&gt;  &lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&amp;gt;&lt;/td&gt;&lt;td&gt;Redirect standard output&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&amp;gt;&amp;gt;&lt;/td&gt;&lt;td&gt;Append to standard output&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2&amp;gt;&lt;/td&gt;&lt;td&gt;Redirect standard error&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2&amp;gt;&amp;amp;1&lt;/td&gt;&lt;td&gt;Redirect standard error to standard ouput&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2&amp;gt;&amp;amp;1|&lt;/td&gt;&lt;td&gt;Redirect standard error to standard ouput, and pipe them to another command&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&amp;lt;&lt;/td&gt;&lt;td&gt;Redirect standard input&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;|&lt;/td&gt;&lt;td&gt;Pipe standard output to another command&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt; &lt;/table&gt;&lt;br /&gt;
Please note that because &amp;lt; and &amp;gt; are referring to standard input and output respectively, the numbers 0 and 1 are not required in this case.</content><link rel='replies' type='application/atom+xml' href='http://yongouyang.blogspot.com/feeds/6743663833095859217/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://yongouyang.blogspot.com/2013/04/io-redirection-in-bash.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/6743663833095859217'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/6743663833095859217'/><link rel='alternate' type='text/html' href='http://yongouyang.blogspot.com/2013/04/io-redirection-in-bash.html' title='I/O Redirection in Bash'/><author><name>Yong Ouyang</name><uri>http://www.blogger.com/profile/05612250828808301428</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3705947190453566253.post-7144174753722155533</id><published>2013-04-04T17:04:00.000+08:00</published><updated>2013-04-04T17:07:53.806+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="benchmark"/><category scheme="http://www.blogger.com/atom/ns#" term="caliper"/><category scheme="http://www.blogger.com/atom/ns#" term="Java"/><category scheme="http://www.blogger.com/atom/ns#" term="performance"/><category scheme="http://www.blogger.com/atom/ns#" term="Sorting"/><title type='text'>Sorting Algorithm Performance Comparisons with Caliper&#39;s Micro Benchmarking</title><content type='html'>After inspired by Martin Thompson&#39;s presentation on &lt;a href=&quot;http://www.infoq.com/presentations/performance-testing-java&quot;&gt;Performance Testing Java Application&lt;/a&gt;, I decided to try out the micro benchmarking framework Caliper on the sorting algorithms that I recently wrote in order to understand better how different sorting algorithms behaves given an array of randomly distributed values.&lt;br /&gt;
&lt;br /&gt;
It was actually a bit involving to find out where I could download the caliper JAR file, as it was not available on their google code base. You can download it from the &lt;a href=&quot;http://mvnrepository.com/artifact/com.google.caliper/caliper&quot;&gt;maven repository&lt;/a&gt;, or grab it from my git described at the bottom of this article.&lt;br /&gt;
&lt;br /&gt;
I created a SortingAlgorithmsBenchmark class that extends SimpleBenchmark, and some public methods, whose names have prefix &#39;time&#39;. Then use the caliper Runner to run the benchmarks on the SortingAlgorithmsBenchmark class, as shown below&lt;br /&gt;
&lt;pre&gt;import com.google.caliper.Runner;
import com.google.caliper.SimpleBenchmark;
import sorting.*;

import java.util.Arrays;
import java.util.Random;

public class SortingAlgorithmsBenchmark extends SimpleBenchmark {

    private static final int SIZE = 10000;
    private static final int MAX_VALUE = 10000;
    private int[] values;

    @Override
    protected void setUp() throws Exception {
        values = new int[SIZE];
        Random generator = new Random();
        for (int i = 0; i &amp;lt; values.length; i++) {
            values[i] = generator.nextInt(MAX_VALUE);
        }
    }

    public void timeBubbleSort(int reps) {
        for (int i = 0; i &amp;lt; reps; i++) {
            BubbleSort.sort(values);
        }
    }

    public void timeInsertionSort(int reps) {
        for (int i = 0; i &amp;lt; reps; i++) {
            InsertionSort.sort(values);
        }
    }

    public void timeSelectionSort(int reps) {
        for (int i = 0; i &amp;lt; reps; i++) {
            SelectionSort.sort(values);
        }
    }

    public void timeMergeSort(int reps) {
        for (int i = 0; i &amp;lt; reps; i++) {
            MergeSort.sort(values);
        }
    }

    public void timeShellSort(int reps) {
        for (int i = 0; i &amp;lt; reps; i++) {
            ShellSort.sort(values);
        }
    }

    public void timeArraysSort(int reps) {
        for (int i = 0; i &amp;lt; reps; i++) {
            Arrays.sort(values);
        }
    }

    public static void main(String[] args) {
        Runner.main(SortingAlgorithmsBenchmark.class, args);
    }

}
&lt;/pre&gt;&lt;br /&gt;
Here are the results when running the benchmarks with a random array of size 10,000. Apparently, bubble sort and selection sort are the slowest of all, with selection sort behaving rather unstable (you will notice the selection sort benchmark is quite different across different runs. It is pleased to see that the sorting algorithm (Dual-Pivot Quick Sort) used by Arrays performs fairly well with a medium size array.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;0% Scenario{vm=java, trial=0, benchmark=BubbleSort} 75703105.85 ns; σ=3428843.80 ns @ 10 trials
17% Scenario{vm=java, trial=0, benchmark=InsertionSort} 73305.66 ns; σ=712.37 ns @ 6 trials
33% Scenario{vm=java, trial=0, benchmark=SelectionSort} 49624130.05 ns; σ=345774.06 ns @ 3 trials
50% Scenario{vm=java, trial=0, benchmark=MergeSort} 478932.15 ns; σ=683.99 ns @ 3 trials
67% Scenario{vm=java, trial=0, benchmark=ShellSort} 262061.27 ns; σ=11605.29 ns @ 10 trials
83% Scenario{vm=java, trial=0, benchmark=ArraysSort} 8063.53 ns; σ=20167.07 ns @ 10 trials

    benchmark       us linear runtime
   BubbleSort 75703.11 ==============================
InsertionSort    73.31 =
SelectionSort 49624.13 ===================
    MergeSort   478.93 =
    ShellSort   262.06 =
   ArraysSort     8.06 =

vm: java
trial: 0
&lt;/pre&gt;&lt;br /&gt;
Increasing the array size to 100,000, and excluding the bubble sort and selection sort in the benckmarks, we have another set of results, where insertion sort starts to behave terribly in this case, and the dual-pivot quick sort is still the quickest.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;0% Scenario{vm=java, trial=0, benchmark=InsertionSort} 2031873339.00 ns; σ=3247182.51 ns @ 3 trials
25% Scenario{vm=java, trial=0, benchmark=MergeSort} 5701257.43 ns; σ=37183.00 ns @ 3 trials
50% Scenario{vm=java, trial=0, benchmark=ShellSort} 2277851.07 ns; σ=21077.62 ns @ 3 trials
75% Scenario{vm=java, trial=0, benchmark=ArraysSort} 210179.59 ns; σ=164843.22 ns @ 10 trials

    benchmark      us linear runtime
InsertionSort 2031873 ==============================
    MergeSort    5701 =
    ShellSort    2278 =
   ArraysSort     210 =

vm: java
trial: 0
&lt;/pre&gt;&lt;br /&gt;
You can find the source code for the sorting algorithms &lt;a href=&quot;https://github.com/yongouyang/DataStructureAndAlgorithms/tree/master/src/main/sorting&quot;&gt;here&lt;/a&gt;, and the benchmarks runner &lt;a href=&quot;https://github.com/yongouyang/DataStructureAndAlgorithms/tree/master/src/test/benchmark&quot;&gt;here&lt;/a&gt;, all of which are part of my github project &lt;a href=&quot;https://github.com/yongouyang/DataStructureAndAlgorithms&quot;&gt;DataStructureAndAlgorithms&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://yongouyang.blogspot.com/feeds/7144174753722155533/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://yongouyang.blogspot.com/2013/04/sorting-algorithm-performance.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/7144174753722155533'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/7144174753722155533'/><link rel='alternate' type='text/html' href='http://yongouyang.blogspot.com/2013/04/sorting-algorithm-performance.html' title='Sorting Algorithm Performance Comparisons with Caliper&#39;s Micro Benchmarking'/><author><name>Yong Ouyang</name><uri>http://www.blogger.com/profile/05612250828808301428</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3705947190453566253.post-5451653580670600117</id><published>2013-04-03T11:47:00.000+08:00</published><updated>2013-04-03T14:24:48.913+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Builder Pattern"/><category scheme="http://www.blogger.com/atom/ns#" term="Groovy"/><category scheme="http://www.blogger.com/atom/ns#" term="Java"/><title type='text'>A Different Builder Pattern Example in Java</title><content type='html'>&lt;p&gt;Builder design pattern is often used to separate the construction of a complex object from its various representations. I will show you a nicer way of writing a Builder pattern, rather than the example shown in the &lt;a href=&quot;http://en.wikipedia.org/wiki/Builder_pattern&quot;&gt;wiki&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;First of all, I created a POJO called Vehicle, which has some simple properties about its model, its make, etc. Then, nested within this POJO, I created a Builder that holds some default properties which can be used to build a vehicle. The builder can be created by a static method newBuilder(), and we can override the vehicle properties by chaining the with* methods, and finally return the constructed vehicle using the build() method.&lt;/p&gt;
&lt;pre&gt;public class Vehicle {

    private String model;
    private String make;
    private int numberOfWheels;
    private double height;
    private double width;
    private double length;
    private int numberOfDoors;

    private Vehicle(String model, String make, int numberOfWheels, double height, double width, double length, int numberOfDoors) {
        this.model = model;
        this.make = make;
        this.numberOfWheels = numberOfWheels;
        this.height = height;
        this.width = width;
        this.length = length;
        this.numberOfDoors = numberOfDoors;
    }

    public static class Builder {

        private String model = &quot;M5&quot;;
        private String make = &quot;BMW&quot;;
        private int numberOfWheels = 4;
        private double height = 1.45;
        private double width = 1.9;
        private double length = 4.62;
        private int numberOfDoors = 5;

        public static Builder newBuilder() {
            return new Builder();
        }

        public Builder withModel(String model) {
            this.model = model;
            return this;
        }

        public Builder withMake(String make) {
            this.make = make;
            return this;
        }

        public Vehicle build() {
            return new Vehicle(model, make, numberOfWheels, height, width,length, numberOfDoors);
        }
    }
}
&lt;/pre&gt;
&lt;p&gt;Let me use a unit test, written in Groovy, to demonstrate exactly how we use the builder. I created a test to show how we can build a default vehicle without providing any overrides to the default vehicle properties, and another test to show how we can override the default vehicle properties to create a different vehicle.&lt;/p&gt;
&lt;pre&gt;import org.junit.Test

class VehicleTest {

    @Test
    public void canBuildADefaultVehicle() {
        def defaultVehicle = Vehicle.Builder.newBuilder().build()
        assert defaultVehicle.model == &quot;M5&quot;
        assert defaultVehicle.make == &quot;BMW&quot;
        assert defaultVehicle.numberOfWheels == 4
        assert defaultVehicle.height == 1.45
        assert defaultVehicle.width == 1.9
        assert defaultVehicle.length == 4.62
        assert defaultVehicle.numberOfDoors == 5
    }

    @Test
    public void canBuildADifferentVehicle() {
        def defaultVehicle = Vehicle.Builder.newBuilder().withModel(&quot;M3&quot;).build()
        assert defaultVehicle.model == &quot;M3&quot;
        assert defaultVehicle.make == &quot;BMW&quot;
        assert defaultVehicle.numberOfWheels == 4
        assert defaultVehicle.height == 1.45
        assert defaultVehicle.width == 1.9
        assert defaultVehicle.length == 4.62
        assert defaultVehicle.numberOfDoors == 5
    }
}
&lt;/pre&gt;
&lt;p&gt;Some says the chaining syntax makes the building block easier to read. :)&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://yongouyang.blogspot.com/feeds/5451653580670600117/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://yongouyang.blogspot.com/2013/04/a-different-builder-pattern-example-in.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/5451653580670600117'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/5451653580670600117'/><link rel='alternate' type='text/html' href='http://yongouyang.blogspot.com/2013/04/a-different-builder-pattern-example-in.html' title='A Different Builder Pattern Example in Java'/><author><name>Yong Ouyang</name><uri>http://www.blogger.com/profile/05612250828808301428</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3705947190453566253.post-9130135683384753902</id><published>2013-04-02T16:57:00.000+08:00</published><updated>2013-04-02T16:59:39.701+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Breadth First Search"/><category scheme="http://www.blogger.com/atom/ns#" term="Depth First Search"/><category scheme="http://www.blogger.com/atom/ns#" term="Directed Graphs"/><category scheme="http://www.blogger.com/atom/ns#" term="Farmer Wolf Goat"/><category scheme="http://www.blogger.com/atom/ns#" term="Graphs"/><category scheme="http://www.blogger.com/atom/ns#" term="Groovy"/><category scheme="http://www.blogger.com/atom/ns#" term="Java"/><category scheme="http://www.blogger.com/atom/ns#" term="Riddle"/><category scheme="http://www.blogger.com/atom/ns#" term="State Space Graph"/><title type='text'>Solving Farmer-Wolf-Goat-Cabbage riddle with Groovy/Java</title><content type='html'>&lt;br /&gt;
&lt;li&gt;&lt;b&gt;The Riddle - Farmer Wolf Goat Cabbage&lt;/b&gt;&lt;/li&gt;
A farmer is on the west bank of a river with a wolf, a goat and a cabbage in his care. Without his presence the wolf would eat
the goat or the goat would eat the cabbage. The wolf is not interested in the cabbage. The farmer wishes to bring his three
charges across the river. However the boat available to him can only carry one of the wolf, goat and cabbage besides
himself. The puzzle is: is there a sequence of river crossings so that the farmer can transfer himself and the other three all
intact to the east bank?
&lt;li&gt;&lt;b&gt;The Solution&lt;/b&gt;&lt;/li&gt;
It is a task that given an initial state, a final state, and a set of rules, one will start from the initial state and try to reach to the final state by passing through some intermediate states. Each move will transform from one state to the other, and there might be multiple valid moves from a given state. Such a collection of interconnected states can be represented by &lt;b&gt;State Space Graph&lt;/b&gt;.
&lt;br /&gt;
Let&#39;s use &#39;f&#39;, &#39;c&#39;, &#39;g&#39;, &#39;w&#39; to denote the farmer, the cabbage, the goat, and the wolf, and use &#39;|&#39; to separate the river where left of the &#39;|&#39; denotes west bank and right of the &#39;|&#39; denotes east bank. Initially, they are all at the west bank of the river, which is represented as &#39;fcgw |&#39; as shown below. We can solve the riddle by figuring out what the possible and valid moves are, using either Breadth-First Search or Depth-First Search, on a state space graph shown below
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmSb-jkT3-v2C5rnihqFm6Q6PPXgTcnqLGcWddi25tXNOm7NXCy1TmW1Utd1nzTC9rHPZAsMinCbjBcbca8FO17FghYrYd2VclgYcTaQsk95cm2ozvNLoFvdL7L5FpV1nE7N2Tbav8wgx7/s1600/Drawing2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmSb-jkT3-v2C5rnihqFm6Q6PPXgTcnqLGcWddi25tXNOm7NXCy1TmW1Utd1nzTC9rHPZAsMinCbjBcbca8FO17FghYrYd2VclgYcTaQsk95cm2ozvNLoFvdL7L5FpV1nE7N2Tbav8wgx7/s320/Drawing2.png&quot; width=&quot;273&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;&amp;nbsp;&lt;/ul&gt;
&lt;br /&gt;
&lt;li&gt;&lt;b&gt;Depth First Search&lt;/b&gt;&lt;/li&gt;
I use DFS to find the first possible solution to the riddle, where it looks like this&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWtpCpmoBfgx_WF-ABoAks3f8M7DIbMgIK1NtSaFT5wuOUq7sOxmPs2c67GCgGg38kVPEpVMw7VOexIQRiVjRv5mKfmR3BOj19JSqMl-TGnrd8MwdrZre-7G3wWccNAltKHKkjz3MNpKuV/s1600/StateSpaceGraph_SimpleDepthFirstSearch.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWtpCpmoBfgx_WF-ABoAks3f8M7DIbMgIK1NtSaFT5wuOUq7sOxmPs2c67GCgGg38kVPEpVMw7VOexIQRiVjRv5mKfmR3BOj19JSqMl-TGnrd8MwdrZre-7G3wWccNAltKHKkjz3MNpKuV/s320/StateSpaceGraph_SimpleDepthFirstSearch.png&quot; width=&quot;251&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
or with a possibility of backtracking like this&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZta1zUidlFPBrCTlAI6GfUAoqg51sMDSOtYlxScwheV5PrsG5yuWs5joeaN61UFElFI2yfkMWbGYy1SBPKQA7WiKt9crwolyJ183lMQmSFUrMu8HrvVTHlNGLW3tKkZBE6DgVcNcc-hwv/s1600/StateSpaceGraph_DepthFirstSearch_Backtracking.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZta1zUidlFPBrCTlAI6GfUAoqg51sMDSOtYlxScwheV5PrsG5yuWs5joeaN61UFElFI2yfkMWbGYy1SBPKQA7WiKt9crwolyJ183lMQmSFUrMu8HrvVTHlNGLW3tKkZBE6DgVcNcc-hwv/s320/StateSpaceGraph_DepthFirstSearch_Backtracking.png&quot; width=&quot;251&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;li&gt;&lt;b&gt;Breadth First Search&lt;/b&gt;&lt;/li&gt;
I can build a complete state space graph using BFS, excluding the red states as shown below&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQhA5eCE0rIPKd2jl6iboT8oOzi_-PMo-j_kLslX1Du0f48Rvd89sSm5hv0B2S08WZRyeMc7vVLXK8pc0EY4Lt8rpK4A6249PPXDUcQzEziRAV_csCBY0l89qbLSBn4tbNt1XhT1KhKmnk/s1600/StateSpaceGraph_BreadthFirstSearch.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQhA5eCE0rIPKd2jl6iboT8oOzi_-PMo-j_kLslX1Du0f48Rvd89sSm5hv0B2S08WZRyeMc7vVLXK8pc0EY4Lt8rpK4A6249PPXDUcQzEziRAV_csCBY0l89qbLSBn4tbNt1XhT1KhKmnk/s320/StateSpaceGraph_BreadthFirstSearch.png&quot; width=&quot;251&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;li&gt;&lt;b&gt;Sample Source Code&lt;/b&gt;&lt;/li&gt;
Implemented in a mix of Groovy and Java, where Java is mainly used for the POJOs, the sample source code, including the unit test, demonstrates how to build a complete state space graph (which is also a directed graph) and how to find all possible solutions based on the state space graph.&lt;br /&gt;
DirectedGraph.java&lt;br /&gt;
&lt;pre&gt;import java.util.*;

public class DirectedGraph&amp;lt;T&amp;gt; implements Iterable&amp;lt;T&amp;gt; {

    // key is a Node, value is a set of Nodes connected by outgoing edges from the key
    private final Map&amp;lt;T, Set&amp;lt;T&amp;gt;&amp;gt; graph = new HashMap&amp;lt;T, Set&amp;lt;T&amp;gt;&amp;gt;();

    public boolean addNode(T node) {
        if (graph.containsKey(node)) {
            return false;
        }

        graph.put(node, new HashSet&amp;lt;T&amp;gt;());
        return true;
    }

    public void addNodes(Collection&amp;lt;T&amp;gt; nodes) {
        for (T node : nodes) {
            addNode(node);
        }
    }

    public void addEdge(T src, T dest) {
        validateSourceAndDestinationNodes(src, dest);

        // Add the edge by adding the dest node into the outgoing edges
        graph.get(src).add(dest);
    }

    public void removeEdge(T src, T dest) {
        validateSourceAndDestinationNodes(src, dest);

        graph.get(src).remove(dest);
    }

    public boolean edgeExists(T src, T dest) {
        validateSourceAndDestinationNodes(src, dest);

        return graph.get(src).contains(dest);
    }

    public Set&amp;lt;T&amp;gt; edgesFrom(T node) {
        // Check that the node exists.
        Set&amp;lt;T&amp;gt; edges = graph.get(node);
        if (edges == null)
            throw new NoSuchElementException(&quot;Source node does not exist.&quot;);

        return Collections.unmodifiableSet(edges);
    }

    public Iterator&amp;lt;T&amp;gt; iterator() {
        return graph.keySet().iterator();
    }

    public int size() {
        return graph.size();
    }

    public boolean isEmpty() {
        return graph.isEmpty();
    }

    private void validateSourceAndDestinationNodes(T src, T dest) {
        // Confirm both endpoints exist
        if (!graph.containsKey(src) || !graph.containsKey(dest))
            throw new NoSuchElementException(&quot;Both nodes must be in the graph.&quot;);
    }

}
&lt;/pre&gt;
BoatLocation.java
&lt;br /&gt;
&lt;pre&gt;public enum BoatLocation {
    WestBank, EastBank
}
&lt;/pre&gt;
RiverRole.java, implemented Comparable interface in order to be used in a SortedSet
&lt;br /&gt;
&lt;pre&gt;public class RiverRole implements Comparable&amp;lt;RiverRole&amp;gt; {

    public final String name;
    public final boolean canSailTheBoat;

    public RiverRole(String name, boolean canSailTheBoat) {
        this.name = name;
        this.canSailTheBoat = canSailTheBoat;
    }

    @Override
    public int compareTo(RiverRole o) {
        return this.name.compareTo(o.name);
    }

    @Override
    public String toString() {
        return name;
    }
}
&lt;/pre&gt;
RiverState.java
&lt;br /&gt;
&lt;pre&gt;import java.util.Collection;
import java.util.SortedSet;
import java.util.TreeSet;

public class RiverState {

    private SortedSet&amp;lt;RiverRole&amp;gt; westBank;
    private SortedSet&amp;lt;RiverRole&amp;gt; eastBank;
    private BoatLocation boatLocation;

    public RiverState(Collection&amp;lt;RiverRole&amp;gt; westBank, Collection&amp;lt;RiverRole&amp;gt; eastBank, BoatLocation boatLocation) {
        this.westBank = new TreeSet&amp;lt;RiverRole&amp;gt;(westBank);
        this.eastBank = new TreeSet&amp;lt;RiverRole&amp;gt;(eastBank);
        this.boatLocation = boatLocation;
    }

    public SortedSet&amp;lt;RiverRole&amp;gt; getWestBank() {
        return new TreeSet&amp;lt;RiverRole&amp;gt;(westBank);
    }

    public SortedSet&amp;lt;RiverRole&amp;gt; getEastBank() {
        return new TreeSet&amp;lt;RiverRole&amp;gt;(eastBank);
    }

    public BoatLocation getBoatLocation() {
        return boatLocation;
    }

    @Override
    public String toString() {
        return &quot;State{westBank=&quot; + westBank + &quot;, eastBank=&quot; + eastBank + &quot;, boatLocation=&quot; + boatLocation + &quot;}&quot;;
    }

    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof RiverState)) return false;

        RiverState riverState = (RiverState) o;

        return eastBank.equals(riverState.eastBank) &amp;amp;&amp;amp;
               westBank.equals(riverState.westBank) &amp;amp;&amp;amp;
               boatLocation.equals(riverState.boatLocation);
    }

    public int hashCode() {
        int result;
        result = westBank.hashCode();
        result = 31 * result + eastBank.hashCode();
        result = 31 * result + boatLocation.hashCode();
        return result;
    }
}
&lt;/pre&gt;
FarmerWolfGoatRiddle.groovy
&lt;br /&gt;
&lt;pre&gt;import graph.DirectedGraph
import org.codehaus.groovy.runtime.MethodClosure

import static fun.rivercrossing.BoatLocation.EastBank
import static fun.rivercrossing.BoatLocation.WestBank

public class FarmerWolfGoatRiddle {

    /*  Farmer Wolf Goat Puzzle
        A farmer is on the east bank of a river with a wolf, goat and cabbage in his care. Without his presence the wolf would eat
        the goat or the goat would eat the cabbage. The wolf is not interested in the cabbage. The farmer wishes to bring his three
        charges across the river. However the boat available to him can only carry one of the wolf, goat and cabbage besides
        himself. The puzzle is: is there a sequence of river crossings so that the farmer can transfer himself and the other three all
        intact to the west bank?
    */

    RiverRole farmer = new RiverRole(&quot;farmer&quot;, true);
    RiverRole wolf = new RiverRole(&quot;wolf&quot;, false);
    RiverRole goat = new RiverRole(&quot;goat&quot;, false);
    RiverRole cabbage = new RiverRole(&quot;cabbage&quot;, false);

    RiverState initialState = new RiverState([farmer, wolf, goat, cabbage], [], BoatLocation.WestBank)
    RiverState finalState = new RiverState([], [farmer, wolf, goat, cabbage], EastBank)

    Closure&amp;lt;Boolean&amp;gt; areRolesHarmonisedOnRiverBank = { Collection&amp;lt;RiverRole&amp;gt; roles -&amp;gt;
        // describe clearly what the rules are
        if (!roles.contains(farmer)) {
            if (roles.contains(wolf) &amp;amp;&amp;amp; roles.contains(goat)) return false
            if (roles.contains(goat) &amp;amp;&amp;amp; roles.contains(cabbage)) return false
        }
        return true
    }


    public Collection&amp;lt;Deque&amp;lt;RiverState&amp;gt;&amp;gt; findAllPossibleSolutions() {
        DirectedGraph&amp;lt;RiverState&amp;gt; graph = buildCompleteGraph()

        Collection&amp;lt;Deque&amp;lt;RiverState&amp;gt;&amp;gt; solutions = []
        Deque&amp;lt;RiverState&amp;gt; currentSolution = new ArrayDeque&amp;lt;RiverState&amp;gt;()

        explore(graph, initialState, currentSolution, solutions)

        return solutions
    }

    // using Depth First Search (Stack Implementation) to identify a solution
    private void explore(DirectedGraph&amp;lt;RiverState&amp;gt; graph, RiverState currentNode, Deque&amp;lt;RiverState&amp;gt; currentSolution, Collection&amp;lt;Deque&amp;lt;RiverState&amp;gt;&amp;gt; solutions) {
        currentSolution.push(currentNode)
        graph.edgesFrom(currentNode).each { RiverState node -&amp;gt;
            if (node == finalState) {
                // add the current solution, including the final node, to the solutions
                currentSolution.push(node)
                solutions.add(new ArrayDeque&amp;lt;RiverState&amp;gt;(currentSolution))
                currentSolution.pop()
            } else {
                // recursively explore
                explore(graph, node, currentSolution, solutions)
            }
        }
        currentSolution.pop()
    }

    // using Breath First Search to build the complete graph
    private DirectedGraph&amp;lt;RiverState&amp;gt; buildCompleteGraph() {
        DirectedGraph&amp;lt;RiverState&amp;gt; graph = new DirectedGraph&amp;lt;RiverState&amp;gt;()
        graph.addNode(initialState)

        Set&amp;lt;RiverState&amp;gt; visitedNodes = new HashSet&amp;lt;RiverState&amp;gt;()

        // use a queue to keep the states to be visited in sequence
        Deque&amp;lt;RiverState&amp;gt; currentStates = new ArrayDeque&amp;lt;RiverState&amp;gt;()
        currentStates.add(initialState)

        while (!currentStates.isEmpty()) {
            if (currentStates.peek() != finalState) {
                def currentState = currentStates.removeFirst()
                if (!visitedNodes.contains(currentState)) {
                    visitedNodes.add(currentState)
                    def possibleStates = findNextPossibleStates(currentState)
                    def validStates = possibleStates.findAll { RiverState possibleState -&amp;gt;
                        // matched state should not be one of the visited states, and it should pass the validations
                        return !visitedNodes.contains(possibleState) &amp;amp;&amp;amp; passRuleValidations(possibleState)
                    }
                    // add successors and edges
                    graph.addNodes(validStates)
                    validStates.each { graph.addEdge(currentState, it) }

                    // add to current states so that we can visit them next
                    currentStates.addAll(validStates)
                }
            } else {
                currentStates.removeFirst() // remove the final state from the currentStates queue
            }
        }

        return graph
    }

    private boolean passRuleValidations(RiverState state) {
        return areRolesHarmonisedOnRiverBank(state.eastBank) &amp;amp;&amp;amp; areRolesHarmonisedOnRiverBank(state.westBank)
    }

    private List&amp;lt;RiverState&amp;gt; findNextPossibleStates(RiverState currentState) {
        // from the last visited state, find out who can sail the boat, and where is the sailor
        List&amp;lt;RiverState&amp;gt; possibleStates = []

        transitFrom(currentState, possibleStates)

        return possibleStates
    }

    private void transitFrom(RiverState currentState, List&amp;lt;RiverState&amp;gt; possibleStates) {
        // check where the boat is
        BoatLocation boatOrigin = currentState.boatLocation
        BoatLocation boatDestination

        // we use method closure to get a copy of west bank or east bank roles
        MethodClosure origin, destination

        // multiple assignments
        (origin, destination, boatDestination) = boatOrigin == WestBank ?
            [currentState.&amp;amp;getWestBank, currentState.&amp;amp;getEastBank, EastBank] :
            [currentState.&amp;amp;getEastBank, currentState.&amp;amp;getWestBank, WestBank]

        def possibleSailors = origin().findAll { RiverRole role -&amp;gt; role.canSailTheBoat }

        possibleSailors?.each { RiverRole sailor -&amp;gt;
            // pick 0 passengers onto the boat
            Collection&amp;lt;RiverRole&amp;gt; onBoat = [sailor]
            possibleStates.add(createNextPossibleState(origin, destination, onBoat, boatDestination))

            Collection&amp;lt;RiverRole&amp;gt; possiblePassengers = origin() as Collection&amp;lt;RiverRole&amp;gt;
            possiblePassengers.remove(sailor)

            // pick 1 passenger onto the boat
            possiblePassengers.each { RiverRole passenger -&amp;gt;
                onBoat = [passenger, sailor]
                possibleStates.add(createNextPossibleState(origin, destination, onBoat, boatDestination))
            }
        }
    }

    private RiverState createNextPossibleState(MethodClosure origin, MethodClosure destination, Collection&amp;lt;RiverRole&amp;gt; onBoat, BoatLocation boatDestination) {
        Collection&amp;lt;RiverRole&amp;gt; newDestination = destination() as Collection&amp;lt;RiverRole&amp;gt;
        Collection&amp;lt;RiverRole&amp;gt; newOrigin = origin() as Collection&amp;lt;RiverRole&amp;gt;

        // boat transits from origin to destination
        newOrigin.removeAll(onBoat)
        newDestination.addAll(onBoat)

        return boatDestination == WestBank ? new RiverState(newDestination, newOrigin, boatDestination) : new RiverState(newOrigin, newDestination, boatDestination)
    }


}
&lt;/pre&gt;
FarmerWolfGoatRiddleTest.groovy
&lt;br /&gt;
&lt;pre&gt;import org.junit.Test

import static fun.rivercrossing.BoatLocation.EastBank
import static fun.rivercrossing.BoatLocation.WestBank


class FarmerWolfGoatRiddleTest {

    FarmerWolfGoatRiddle riddle = new FarmerWolfGoatRiddle()

    @Test
    public void findAllPossibleSolutions() {
        def solutions = riddle.findAllPossibleSolutions()
        // the ordering of solutions will be random
        assert solutions.size() == 2
        assert solutions[0].size() == 8
        assert solutions[1].size() == 8

        def assertAllSolutions = { Deque&amp;lt;RiverState&amp;gt; solution1, Deque&amp;lt;RiverState&amp;gt; solution2 -&amp;gt;
            assertFirstSolution(solution1)
            assertSecondSolution(solution2)
        }

        // assert with the correct expectations regardless of which is the first solution
        if (solutions[0].contains(new RiverState([riddle.wolf], [riddle.farmer, riddle.goat, riddle.cabbage], EastBank))) {
            assertAllSolutions(solutions[0], solutions[1])
        } else {
            assertAllSolutions(solutions[1], solutions[0])
        }
    }

    private void assertFirstSolution(Deque&amp;lt;RiverState&amp;gt; solution) {
        assert solution.poll() == new RiverState([riddle.farmer, riddle.wolf, riddle.goat, riddle.cabbage], [], WestBank)
        assert solution.poll() == new RiverState([riddle.wolf, riddle.cabbage], [riddle.farmer, riddle.goat], EastBank)
        assert solution.poll() == new RiverState([riddle.farmer, riddle.wolf, riddle.cabbage], [riddle.goat], WestBank)
        assert solution.poll() == new RiverState([riddle.wolf], [riddle.farmer, riddle.goat, riddle.cabbage], EastBank)
        assert solution.poll() == new RiverState([riddle.farmer, riddle.wolf, riddle.goat], [riddle.cabbage], WestBank)
        assert solution.poll() == new RiverState([riddle.goat], [riddle.farmer, riddle.wolf, riddle.cabbage], EastBank)
        assert solution.poll() == new RiverState([riddle.farmer, riddle.goat], [riddle.wolf, riddle.cabbage], WestBank)
        assert solution.poll() == new RiverState([], [riddle.farmer, riddle.wolf, riddle.goat, riddle.cabbage], EastBank)
        assert solution.poll() == null
    }

    private void assertSecondSolution(Deque&amp;lt;RiverState&amp;gt; solution) {
        assert solution.poll() == new RiverState([riddle.farmer, riddle.wolf, riddle.goat, riddle.cabbage], [], WestBank)
        assert solution.poll() == new RiverState([riddle.wolf, riddle.cabbage], [riddle.farmer, riddle.goat], EastBank)
        assert solution.poll() == new RiverState([riddle.farmer, riddle.wolf, riddle.cabbage], [riddle.goat], WestBank)
        assert solution.poll() == new RiverState([riddle.cabbage], [riddle.farmer, riddle.goat, riddle.wolf], EastBank)
        assert solution.poll() == new RiverState([riddle.farmer, riddle.cabbage, riddle.goat], [riddle.wolf], WestBank)
        assert solution.poll() == new RiverState([riddle.goat], [riddle.farmer, riddle.wolf, riddle.cabbage], EastBank)
        assert solution.poll() == new RiverState([riddle.farmer, riddle.goat], [riddle.wolf, riddle.cabbage], WestBank)
        assert solution.poll() == new RiverState([], [riddle.farmer, riddle.wolf, riddle.goat, riddle.cabbage], EastBank)
        assert solution.poll() == null
    }
}
&lt;/pre&gt;
</content><link rel='replies' type='application/atom+xml' href='http://yongouyang.blogspot.com/feeds/9130135683384753902/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://yongouyang.blogspot.com/2013/04/solving-farmer-wolf-goat-cabbage-riddle.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/9130135683384753902'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/9130135683384753902'/><link rel='alternate' type='text/html' href='http://yongouyang.blogspot.com/2013/04/solving-farmer-wolf-goat-cabbage-riddle.html' title='Solving Farmer-Wolf-Goat-Cabbage riddle with Groovy/Java'/><author><name>Yong Ouyang</name><uri>http://www.blogger.com/profile/05612250828808301428</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmSb-jkT3-v2C5rnihqFm6Q6PPXgTcnqLGcWddi25tXNOm7NXCy1TmW1Utd1nzTC9rHPZAsMinCbjBcbca8FO17FghYrYd2VclgYcTaQsk95cm2ozvNLoFvdL7L5FpV1nE7N2Tbav8wgx7/s72-c/Drawing2.png" height="72" width="72"/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3705947190453566253.post-3661094989677369579</id><published>2013-03-31T19:02:00.000+08:00</published><updated>2013-03-31T21:21:58.602+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Fibonacci"/><category scheme="http://www.blogger.com/atom/ns#" term="Java"/><category scheme="http://www.blogger.com/atom/ns#" term="python"/><title type='text'>Fibonacci numbers in Python and Java</title><content type='html'>&lt;a href=&quot;http://en.wikipedia.org/wiki/Fibonacci_number&quot;&gt;Fibonacci numbers&lt;/a&gt;,&amp;nbsp; introduced by &lt;a href=&quot;http://en.wikipedia.org/wiki/Fibonacci&quot;&gt;Leonardo Pisano Bigollo&lt;/a&gt; nearly a thousand years ago, were used to solve a fascinating puzzle about the growth of an idealised rabbit population. Below are the first 11 Fibonacci numbers F&lt;sub&gt;n&lt;/sub&gt; where n=0, 1, 2,..., 10:
&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; border=&quot;1&quot; style=&quot;text-align: center;&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;sequence&lt;/td&gt;&lt;td width=&quot;20px;&quot;&gt;F&lt;sub&gt;0&lt;/sub&gt;&lt;/td&gt;&lt;td width=&quot;20px;&quot;&gt;F&lt;sub&gt;1&lt;/sub&gt;&lt;/td&gt;&lt;td width=&quot;20px;&quot;&gt;F&lt;sub&gt;2&lt;/sub&gt;&lt;/td&gt;&lt;td width=&quot;20px;&quot;&gt;F&lt;sub&gt;3&lt;/sub&gt;&lt;/td&gt;&lt;td width=&quot;20px;&quot;&gt;F&lt;sub&gt;4&lt;/sub&gt;&lt;/td&gt;&lt;td width=&quot;20px;&quot;&gt;F&lt;sub&gt;5&lt;/sub&gt;&lt;/td&gt;&lt;td width=&quot;20px;&quot;&gt;F&lt;sub&gt;6&lt;/sub&gt;&lt;/td&gt;&lt;td width=&quot;20px;&quot;&gt;F&lt;sub&gt;7&lt;/sub&gt;&lt;/td&gt;&lt;td width=&quot;20px;&quot;&gt;F&lt;sub&gt;8&lt;/sub&gt;&lt;/td&gt;&lt;td width=&quot;20px;&quot;&gt;F&lt;sub&gt;9&lt;/sub&gt;&lt;/td&gt;&lt;td width=&quot;20px;&quot;&gt;F&lt;sub&gt;10&lt;/sub&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;number&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;8&lt;/td&gt;&lt;td&gt;13&lt;/td&gt;&lt;td&gt;21&lt;/td&gt;&lt;td&gt;34&lt;/td&gt;&lt;td&gt;55&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
or we can describe the Fibonacci numbers as
&lt;br /&gt;
&lt;pre&gt;F&lt;sub&gt;n&lt;/sub&gt; = F&lt;sub&gt;n-1&lt;/sub&gt; + F&lt;sub&gt;n-2&lt;/sub&gt; (when n&amp;gt;=2)
&lt;/pre&gt;
To write a program to return a Fibonacci number given a sequence, there are many possible implementations. I shall present 2 solutions implemented in both Python and Java, where the first one is using recursion, and the second one is using a while loop, however, the performances of these 2 solutions are drastically different when the sequence is bigger.
&lt;br /&gt;
Below are the results when running a Python test script. The recursion way is already showing very poor performance comparing to the while loop way.  
&lt;br /&gt;
&lt;pre&gt;&amp;gt; python test_fib.py 
.Working out Fibonacci(40)=102334155 recursively took 67.310534 seconds
.Working out Fibonacci(40)=102334155 with while loop took 1.8e-05 seconds
Working out Fibonacci(50)=12586269025 with while loop took 1.6e-05 seconds
Working out Fibonacci(60)=1548008755920 with while loop took 1.8e-05 seconds
..
----------------------------------------------------------------------
Ran 4 tests in 67.312s

OK
&lt;/pre&gt;
If we look at the results when running a similar timed test in Java, the same recursion is not as bad as in Python, though still far poorer than the while loop implementation.
&lt;br /&gt;
&lt;pre&gt;&amp;gt; /somewhere/jdk1.6.0_33/bin/java -classpath &quot;.:&quot; fun.Fib
Working out Fibonacci(40)=102334155 recursively took 408 ms
Working out Fibonacci(40)=102334155 with while loop took 2033 ns
Working out Fibonacci(50)=12586269025 with while loop took 2115 ns
Working out Fibonacci(60)=1548008755920 with while loop took 2368 ns
&lt;/pre&gt;
The reason why recursion is slow in this case is because there are a lot of duplicated operations as the sequence grows. For example, to solve F(5), we need to solve F(4) once, F(3) twice, F(2) three times, and F(1) twice, as shown below&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRfXpnNJzpSNmCOILL2mkajI8pQ-08TbQKEnH1TkqEiGO9oMStTzpjob5UUSJ7-4XNATuH5b19emIAIzMQOA1f3PfR9kaM7xlvtihQAHzvll1ul3nLuf9cs6ZGme52EH2N6jl8nxw5FN8J/s1600/Drawing1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRfXpnNJzpSNmCOILL2mkajI8pQ-08TbQKEnH1TkqEiGO9oMStTzpjob5UUSJ7-4XNATuH5b19emIAIzMQOA1f3PfR9kaM7xlvtihQAHzvll1ul3nLuf9cs6ZGme52EH2N6jl8nxw5FN8J/s1600/Drawing1.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
or the number of recursion required given a sequence n is
&lt;br /&gt;
&lt;pre&gt;[1+(n-2)]*(n-2)/2 + (n-3) or n&lt;sup&gt;2&lt;/sup&gt;/2-n/2-2  (when n&amp;gt;=4)
&lt;/pre&gt;
The complexity of using recursion is then actually O(n&lt;sup&gt;2&lt;/sup&gt;), where, on the other hand, the while loop is O(n).
&lt;br /&gt;
Below are the source code that are used in the test.
&lt;br /&gt;
fib.py
&lt;br /&gt;
&lt;pre&gt;import datetime


class Fib:
    def recursively(self, n):
        if n == 0:
            return 0
        elif n &amp;lt;= 2:
            return 1
        else:
            return self.recursively(n - 1) + self.recursively(n - 2)

    def whileLoop(self, n):
        if n == 0:
            return 0
        previous, fib, currentIndex = 0, 1, 1
        while currentIndex &amp;lt; n:
            previous, fib = fib, previous + fib
            currentIndex += 1

        return fib

    def timedRecursively(self, n):
        start = datetime.datetime.now()
        result = self.recursively(n)
        end = datetime.datetime.now()
        elapsed = end - start
        print &quot;Working out Fibonacci({})={} recursively took {} seconds&quot;.format(str(n), str(result), str(elapsed.total_seconds()))
        return result

    def timedWhileLoop(self, n):
        start = datetime.datetime.now()
        result = self.whileLoop(n)
        end = datetime.datetime.now()
        elapsed = end - start
        print &quot;Working out Fibonacci({})={} with while loop took {} seconds&quot;.format(str(n), str(result), str(elapsed.total_seconds()))
        return result
&lt;/pre&gt;
&lt;br /&gt;
test_fib.py
&lt;br /&gt;
&lt;pre&gt;import unittest
from fib import Fib


class TestFib(unittest.TestCase):
    def setUp(self):
        self.fib = Fib()

    def test_recursively(self):
        self.assertEqual(self.fib.recursively(0), 0)
        self.assertEqual(self.fib.recursively(1), 1)
        self.assertEqual(self.fib.recursively(2), 1)
        self.assertEqual(self.fib.recursively(3), 2)
        self.assertEqual(self.fib.recursively(4), 3)
        self.assertEqual(self.fib.recursively(5), 5)
        self.assertEqual(self.fib.recursively(6), 8)
        self.assertEqual(self.fib.recursively(7), 13)
        self.assertEqual(self.fib.recursively(8), 21)
        self.assertEqual(self.fib.recursively(9), 34)
        self.assertEqual(self.fib.recursively(10), 55)

    def test_whileLoop(self):
        self.assertEqual(self.fib.whileLoop(0), 0)
        self.assertEqual(self.fib.whileLoop(1), 1)
        self.assertEqual(self.fib.whileLoop(2), 1)
        self.assertEqual(self.fib.whileLoop(3), 2)
        self.assertEqual(self.fib.whileLoop(4), 3)
        self.assertEqual(self.fib.whileLoop(5), 5)
        self.assertEqual(self.fib.whileLoop(6), 8)
        self.assertEqual(self.fib.whileLoop(7), 13)
        self.assertEqual(self.fib.whileLoop(8), 21)
        self.assertEqual(self.fib.whileLoop(9), 34)
        self.assertEqual(self.fib.whileLoop(10), 55)

    def test_timedRecursively(self):
        self.assertEqual(self.fib.timedRecursively(40), 102334155)

    def test_timedWhileLoop(self):
        self.assertEqual(self.fib.timedWhileLoop(40), 102334155)
        self.assertEqual(self.fib.timedWhileLoop(50), 12586269025)
        self.assertEqual(self.fib.timedWhileLoop(60), 1548008755920)

unittest.main()
&lt;/pre&gt;
&lt;br /&gt;
Fib.java
&lt;br /&gt;
&lt;pre&gt;package fun;

public class Fib {


    public static void main(String[] args) {
        recursively(1);
        whileLoop(1);

        long start = System.nanoTime();

        long result = recursively(40);
        long elapsed = (System.nanoTime() - start) / 1000000;
        System.out.println(String.format(&quot;Working out Fibonacci(%s)=%s recursively took %s ms&quot;, 40, result, elapsed));

        start = System.nanoTime();
        result = whileLoop(40);
        elapsed = (System.nanoTime() - start);
        System.out.println(String.format(&quot;Working out Fibonacci(%s)=%s with while loop took %s ns&quot;, 40, result, elapsed));

        start = System.nanoTime();
        result = whileLoop(50);
        elapsed = (System.nanoTime() - start);
        System.out.println(String.format(&quot;Working out Fibonacci(%s)=%s with while loop took %s ns&quot;, 50, result, elapsed));

        start = System.nanoTime();
        result = whileLoop(60);
        elapsed = (System.nanoTime() - start);
        System.out.println(String.format(&quot;Working out Fibonacci(%s)=%s with while loop took %s ns&quot;, 60, result, elapsed));
    }

    static long recursively(long i) {
        if (i == 0) return 0;
        if (i &amp;lt;= 2) return 1;
        else return recursively(i - 1) + recursively(i - 2);
    }

    static long whileLoop(long i) {
        long previous = 0, fib = 1, currentIndex = 1;
        while (currentIndex &amp;lt; i) {
            long newFib = previous + fib;
            previous = fib;
            fib = newFib;
            currentIndex++;
        }
        return fib;
    }
}
&lt;/pre&gt;
</content><link rel='replies' type='application/atom+xml' href='http://yongouyang.blogspot.com/feeds/3661094989677369579/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://yongouyang.blogspot.com/2013/03/fibonacci-numbers-in-python-and-java.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/3661094989677369579'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/3661094989677369579'/><link rel='alternate' type='text/html' href='http://yongouyang.blogspot.com/2013/03/fibonacci-numbers-in-python-and-java.html' title='Fibonacci numbers in Python and Java'/><author><name>Yong Ouyang</name><uri>http://www.blogger.com/profile/05612250828808301428</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRfXpnNJzpSNmCOILL2mkajI8pQ-08TbQKEnH1TkqEiGO9oMStTzpjob5UUSJ7-4XNATuH5b19emIAIzMQOA1f3PfR9kaM7xlvtihQAHzvll1ul3nLuf9cs6ZGme52EH2N6jl8nxw5FN8J/s72-c/Drawing1.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3705947190453566253.post-8067644650734046526</id><published>2013-03-30T20:29:00.001+08:00</published><updated>2013-04-03T10:24:52.000+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Java"/><category scheme="http://www.blogger.com/atom/ns#" term="python"/><category scheme="http://www.blogger.com/atom/ns#" term="python vs java"/><title type='text'>First impression of Python </title><content type='html'>Born some two decades ago, Python has certainly accumulated enough interests to become one of the most popular programming languages used in the financial industry.&lt;br /&gt;
&lt;br /&gt;
Designed to be a write-less-do-more language, Python has certain aspects that differ from Java:&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;It is an interpreted language, which means no compilation is required.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;It is not a strongly typed language&lt;/li&gt;
&lt;li&gt;Its statement grouping is done by indentation instead of open and close braces&lt;/li&gt;
&lt;li&gt;It does not require declaration of variable or argument&lt;/li&gt;
&lt;li&gt;It supports complex number, for example (using Python interactive interpreter)&lt;/li&gt;
&lt;pre&gt;&lt;span style=&quot;color: #b45f06;&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: #38761d;&quot;&gt;1&lt;/span&gt;j + &lt;span style=&quot;color: #38761d;&quot;&gt;2&lt;/span&gt;J
(-2+0j)
&lt;span style=&quot;color: #b45f06;&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; (&lt;span style=&quot;color: #38761d;&quot;&gt;1&lt;/span&gt;+&lt;span style=&quot;color: #38761d;&quot;&gt;2&lt;/span&gt;j) * complex(&lt;span style=&quot;color: #38761d;&quot;&gt;2&lt;/span&gt;,&lt;span style=&quot;color: #38761d;&quot;&gt;3&lt;/span&gt;)
(-4+7j)
&lt;/pre&gt;
&lt;li&gt;Strings can be subscripted. For example, the first character of a string has index 0.&lt;/li&gt;
&lt;pre&gt;&lt;span style=&quot;color: #b45f06;&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; word=&quot;HelloWorld&quot;
&lt;span style=&quot;color: #b45f06;&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; word[4]
&#39;o&#39;
&lt;span style=&quot;color: #b45f06;&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; word[1:3]   # using the slice notation, returning characters from index 1 to 2
&#39;el&#39;
&lt;/pre&gt;
&lt;li&gt;It supports multiple assignment, for example, &#39;a,b=b,a+b&#39;, where the expression on the right-hand side &#39;b,a+b&#39; are evaluated first before any of the assignments take place&lt;/li&gt;
&lt;li&gt;Not surprisingly, it supports lamda forms&lt;/li&gt;
&lt;pre&gt;&lt;span style=&quot;color: #b45f06;&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: #38761d;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0b5394;&quot;&gt;incresedBy&lt;/span&gt;(n):
...     &lt;span style=&quot;color: #38761d;&quot;&gt;return lambda&lt;/span&gt; x: x + n
...
&lt;span style=&quot;color: #b45f06;&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; f = &lt;span style=&quot;color: #0b5394;&quot;&gt;incresedBy&lt;/span&gt;(42)
&lt;span style=&quot;color: #b45f06;&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; f(1)
43
&lt;/pre&gt;
&lt;li&gt;It supports map and reduce functions as part of its functional programming offerings&lt;/li&gt;
&lt;li&gt;It supports Tuples, which are immutable and usually contain an heterogeneous sequence of elements&lt;/li&gt;
&lt;pre&gt;&lt;span style=&quot;color: #b45f06;&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; t=123,321,&#39;hello&#39;
&lt;span style=&quot;color: #b45f06;&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; t
(123, 321, &#39;hello&#39;)
&lt;/pre&gt;
&lt;li&gt;It allows multiple inheritance, for example&lt;/li&gt;
&lt;pre&gt;class DerivedClassName(Base1, Base2, Base3):
    &amp;lt;statement-1&amp;gt;
    .
    .
    .
    &amp;lt;statement-N&amp;gt;
&lt;/pre&gt;
&lt;/ol&gt;
</content><link rel='replies' type='application/atom+xml' href='http://yongouyang.blogspot.com/feeds/8067644650734046526/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://yongouyang.blogspot.com/2013/03/first-impression-of-python.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/8067644650734046526'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/8067644650734046526'/><link rel='alternate' type='text/html' href='http://yongouyang.blogspot.com/2013/03/first-impression-of-python.html' title='First impression of Python '/><author><name>Yong Ouyang</name><uri>http://www.blogger.com/profile/05612250828808301428</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3705947190453566253.post-8149237946841336327</id><published>2013-03-30T15:39:00.002+08:00</published><updated>2013-03-30T15:39:31.477+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="sed"/><category scheme="http://www.blogger.com/atom/ns#" term="unix"/><title type='text'>Useful Sed command examples in UNIX</title><content type='html'>&lt;ol&gt;
&lt;li&gt;&lt;b&gt;Substitute a regular expression into a new value&lt;/b&gt;&lt;/li&gt;
A simple example is to change the first occurrence of &#39;old&#39; on each line from file1 to &#39;new&#39; and save as file2
&lt;pre&gt;sed &#39;s|old|new|&#39; &amp;lt; file1 &amp;gt; file2&lt;/pre&gt;
where &#39;s&#39; is the substitute command, &#39;|&#39; is the delimiter, &#39;old&#39; is the search pattern in regular expression, and &#39;new&#39; is the replacement string. We can also test string substitution using &#39;echo&#39; like this
&lt;pre&gt;echo &quot;old, and some other old stuffs&quot; | sed &#39;s|old|new|&#39;&lt;/pre&gt;
which will output &#39;new, and some other old stuffs&#39;. Note that in this case it only replace the first occurrence of &#39;old&#39; with &#39;new&#39;. If we want to replace all &#39;old&#39; with &#39;new&#39;, we could append a global replacement symbol &#39;g&#39; after the last delimiter &#39;|&#39;
&lt;pre&gt;echo &quot;old, and some other old stuffs&quot; | sed &#39;s|old|new|g&#39;&lt;/pre&gt;
which will output &#39;new, and some other new stuffs&#39;
&lt;li&gt;&lt;b&gt;Pick any delimiter you like&lt;/b&gt;&lt;/li&gt;
We were using &#39;|&#39; as the delimiter in the above examples. In fact, we can pick any character as the delimiter, as long as it is not in the string we are looking for. For example,
&lt;pre&gt;echo &quot;old, and some other old stuffs&quot; | sed &#39;s/old/new/g&#39;
echo &quot;old, and some other old stuffs&quot; | sed &#39;s:old:new:g&#39;
&lt;/pre&gt;
have the same effect.
&lt;li&gt;&lt;b&gt;Use &amp;amp; as the matched string&lt;/b&gt;&lt;/li&gt;
We could search for a pattern and add some characters on top of the original string like this
&lt;pre&gt;echo &quot;old, and some other old stuffs&quot; | sed &#39;s|[a-z]*|(&amp;amp;)|&#39;&lt;/pre&gt;
which will output &#39;(old), and some other old stuffs&#39;. The special character &#39;&amp;amp;&#39; represents the matching pattern. We could have any number of &#39;&amp;amp;&#39; in the replacement string
&lt;pre&gt;echo &quot;old, 123 and 456 some other old stuffs&quot; | sed -r &#39;s|[0-9]+|&amp;amp; &amp;amp;|&#39;&lt;/pre&gt;
which will output &#39;old, 123 123 and 456 some other old stuffs&#39;. Note that we use &#39;-r&#39; here to indicate we are using extended regular expression such that sed will support the use of &#39;+&#39;.
&lt;/ol&gt;
</content><link rel='replies' type='application/atom+xml' href='http://yongouyang.blogspot.com/feeds/8149237946841336327/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://yongouyang.blogspot.com/2013/03/useful-sed-command-examples-in-unix.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/8149237946841336327'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/8149237946841336327'/><link rel='alternate' type='text/html' href='http://yongouyang.blogspot.com/2013/03/useful-sed-command-examples-in-unix.html' title='Useful Sed command examples in UNIX'/><author><name>Yong Ouyang</name><uri>http://www.blogger.com/profile/05612250828808301428</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3705947190453566253.post-2315770632907971805</id><published>2013-03-29T21:04:00.000+08:00</published><updated>2013-03-30T14:16:28.479+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="find"/><category scheme="http://www.blogger.com/atom/ns#" term="unix"/><title type='text'>Useful Find command examples in UNIX</title><content type='html'>Find command is one of the most useful commands in UNIX, as there are many options out there to accomplish various search tasks.&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Find files which have been modified for more than or less than a certain time &lt;/li&gt;
We can use &#39;find * -mtime n&#39; to search files under current directory based on modification time. The numeric argument n can be specified as +n, meaning greater than n days; -n, meaning less than n days; or n, meaning exactly n days. For example, &lt;br /&gt;
to find files which were last modified for more than 30 days ago
&lt;pre&gt;find . -mtime +30&lt;/pre&gt;
to find files which were last modified for less than 15 days ago
&lt;pre&gt;find . -mtime -15&lt;/pre&gt;
to find files which were last modified for exactly 10 days ago
&lt;pre&gt;find . -mtime 10&lt;/pre&gt;
There are other options like 
&lt;pre&gt;-mmin n, which refers to file&#39;s data was last modified n minutes ago
-amin n, which refers to file&#39;s data was last accessed n minutes ago
-atime n, which refers to file&#39;s data was last accessed n days ago
-type f, which searches for regular file
-type d, which searches for directory,
-exec command, which executes command by passing in the find results,
-perm /mode, which searches files with given permission 
&lt;/pre&gt;
&lt;li&gt;Remove files which are older than n days&lt;/li&gt;
Since we understand how to search for files which were last modified for more than n days, we can then use the rm command to remove them
&lt;pre&gt;find /some-dir/* -mtimes +30 -type f -exec rm {} \;
&lt;/pre&gt;
&#39;-exec&#39; is used to pass in commands like &#39;rm&#39;; &#39;{}&#39; is replaced by the file name that &#39;find&#39; returns; and the &#39;-exec&#39; command has to end with &#39;\;&#39;. &lt;br/&gt;
Another way will be
&lt;pre&gt;find /some-dir/* -mtimes +30 -type f -print0 | xargs -0 rm&lt;/pre&gt;
where &#39;xargs&#39; reads &#39;find&#39; results and execute &#39;rm&#39; on each of the &#39;find&#39; results
&lt;li&gt;Find files which contain particular strings&lt;/li&gt;
Below is an example to search all txt files starting from current directory for string &quot;some-string&quot;
&lt;pre&gt;find . -name &quot;*.txt&quot; -print | xargs grep &quot;some-string&quot;
&lt;/pre&gt;
&lt;/ul&gt;
</content><link rel='replies' type='application/atom+xml' href='http://yongouyang.blogspot.com/feeds/2315770632907971805/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://yongouyang.blogspot.com/2013/03/useful-find-command-examples-in-unix.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/2315770632907971805'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/2315770632907971805'/><link rel='alternate' type='text/html' href='http://yongouyang.blogspot.com/2013/03/useful-find-command-examples-in-unix.html' title='Useful Find command examples in UNIX'/><author><name>Yong Ouyang</name><uri>http://www.blogger.com/profile/05612250828808301428</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3705947190453566253.post-795833852155950428</id><published>2013-03-29T17:00:00.000+08:00</published><updated>2013-03-29T17:00:16.373+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="python"/><category scheme="http://www.blogger.com/atom/ns#" term="unix"/><title type='text'>Using Python SimpleHTTPServer to share files</title><content type='html'>There are cases when I want to share some files within the intranet to other users. &lt;br /&gt;
&lt;br /&gt;
Python comes with a simple built-in module called SimpleHTTPServer that can turn any directory in the system into the web server directory. I literally just need a single command line to accomplish this task, given Python is shipped with openSUSE!&lt;br /&gt;
&lt;br /&gt;
Assuming I am running linux, and I want to share my home directory ~&lt;br /&gt;
&lt;pre&gt;cd ~&lt;/pre&gt;
Start up the http server on port 10001
&lt;br /&gt;
&lt;pre&gt;youyang@monkey-dev-01:~&amp;gt; python -m SimpleHTTPServer 10001&lt;/pre&gt;
Now the http server is running on port 10001. Open a browser and type the following address, where monkey-dev-01 happens to be my hostname
&lt;br /&gt;
&lt;pre&gt;http://monkey-dev-01:10001&lt;/pre&gt;
Since there is no index.html under my home directory, the files in the home directory will be listed. Now my purpose is served, but there is one slight problem -- the program is running on the foreground, meaning I can&#39;t do anything on that open terminal as it continues to display the http requests when I browse the directories. To change the running process from foreground to background, I need to press CTRL+Z to pause the process, as shown below
&lt;br /&gt;
&lt;pre&gt;^Z
[1]+  Stopped                 python -m SimpleHTTPServer 10001
&lt;/pre&gt;
and type &#39;bg&#39; to move the process to run in the background
&lt;br /&gt;
&lt;pre&gt;youyang@monkey-dev-01:~&amp;gt; bg
[1]+ python -m SimpleHTTPServer 10001 &amp;amp;
&lt;/pre&gt;
We can also use &#39;jobs -l&#39; to display the jobs in current session
&lt;br /&gt;
&lt;pre&gt;youyang@monkey-dev-01:~&amp;gt; jobs -l
[1]+  4127 Running                 python -m SimpleHTTPServer 10001 &amp;amp;
&lt;/pre&gt;
We can also start up the http server running in the background directly, by appending a &#39;&amp;amp;&#39; at the end of the command
&lt;br /&gt;
&lt;pre&gt;youyang@monkey-dev-01:~&amp;gt; python -m SimpleHTTPServer 10001&amp;amp;&lt;/pre&gt;
</content><link rel='replies' type='application/atom+xml' href='http://yongouyang.blogspot.com/feeds/795833852155950428/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://yongouyang.blogspot.com/2013/03/using-python-simplehttpserver-to-share.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/795833852155950428'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/795833852155950428'/><link rel='alternate' type='text/html' href='http://yongouyang.blogspot.com/2013/03/using-python-simplehttpserver-to-share.html' title='Using Python SimpleHTTPServer to share files'/><author><name>Yong Ouyang</name><uri>http://www.blogger.com/profile/05612250828808301428</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3705947190453566253.post-577159155050511123</id><published>2013-03-29T16:20:00.000+08:00</published><updated>2013-03-29T18:01:29.280+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="unix"/><category scheme="http://www.blogger.com/atom/ns#" term="unix cheat sheet"/><title type='text'>Unix Cheat Sheet</title><content type='html'>&lt;table&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td colspan=&quot;3&quot;&gt;&lt;hr /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot;&gt;List a directory&lt;/td&gt;&lt;td&gt;Alternatively, type &#39;ls --help&#39; or &#39;man ls&#39; for more information&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;ls [path]&lt;/td&gt;&lt;td&gt;list given path without any options. Without the path, it is listing current directory&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;ls -l [path]&lt;/td&gt;&lt;td&gt;list given path in long listing format&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;ls -h [path]&lt;/td&gt;&lt;td&gt;list given path in human readable format&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;ls -a [path]&lt;/td&gt;&lt;td&gt;list given path, including hidden files (which has prefix dot)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;ls -lrt [path]&lt;/td&gt;&lt;td&gt;list given path, combining different options. long listing format, sort by modification time in reverse order&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;ls [path]  &lt;filename&gt;&lt;/filename&gt;&lt;/td&gt;&lt;td&gt;list given path, redirect listing results into a file&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;ls [path] | more&lt;/td&gt;&lt;td&gt;list given path, showing listing results on one screen at a time&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;3&quot;&gt;&lt;hr /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;3&quot;&gt;Change to a directory&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;cd &amp;lt;directory&amp;gt;&lt;/td&gt;&lt;td&gt;change to the given directory&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;cd ~&lt;/td&gt;&lt;td&gt;change to user&#39;s home directory&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;cd /&lt;/td&gt;&lt;td&gt;change to root directory&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;cd ..&lt;/td&gt;&lt;td&gt;go to parent directory&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;cd ../&amp;lt;directory&amp;gt;&lt;/td&gt;&lt;td&gt;go to a sibling directory&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;3&quot;&gt;&lt;hr /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;3&quot;&gt;Print current working directory&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;pwd&lt;/td&gt;&lt;td&gt;display the current working directory&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;3&quot;&gt;&lt;hr /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;3&quot;&gt;Create directory(ies)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;mkdir &amp;lt;directory&amp;gt;&lt;/td&gt;&lt;td&gt;create the directory under current working directory&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;mkdir -p &amp;lt;dir1&amp;gt;/&amp;lt;dir2&amp;gt;&lt;/td&gt;&lt;td&gt;create directory2 under directory1; create parent directory2 as needed&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;3&quot;&gt;&lt;hr /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;3&quot;&gt;Remove files or directory(ies)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;rm &amp;lt;file&amp;gt;&lt;/td&gt;&lt;td&gt;remove the file&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;rm -rf &amp;lt;directory&amp;gt;&lt;/td&gt;&lt;td&gt;remove the contents of given directory recursively without prompt&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;3&quot;&gt;&lt;hr /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;3&quot;&gt;Move a file or a directory&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;mv &amp;lt;source&amp;gt; &amp;lt;dest&amp;gt;&lt;/td&gt;&lt;td&gt;rename source as dest, and move source to dest&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;3&quot;&gt;&lt;hr /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;3&quot;&gt;Copy a file or a directory&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;cp &amp;lt;source&amp;gt; &amp;lt;dest&amp;gt;&lt;/td&gt;&lt;td&gt;make a copy from source to dest&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;cp -r &amp;lt;source&amp;gt; &amp;lt;dest&amp;gt;&lt;/td&gt;&lt;td&gt;copy recursively from source directory to dest directory&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;3&quot;&gt;&lt;hr /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;3&quot;&gt;Download a file from http website&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;wget &amp;lt;url&amp;gt;&lt;/td&gt;&lt;td&gt;download the resource to current directory&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;curl &amp;lt;url&amp;gt;&lt;/td&gt;&lt;td&gt;download the resource to current directory&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;3&quot;&gt;&lt;hr /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;3&quot;&gt;View a text file&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;less &amp;lt;file&amp;gt;&lt;/td&gt;&lt;td&gt;view file page by page, with a lot of features&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;more &amp;lt;file&amp;gt;&lt;/td&gt;&lt;td&gt;view file with screen length&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;cat &amp;lt;file&amp;gt;&lt;/td&gt;&lt;td&gt;view file, but it will scroll to the end of file&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;cat &amp;lt;file&amp;gt; | more&lt;/td&gt;&lt;td&gt;view file, and piped the file content to more command&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;3&quot;&gt;&lt;hr /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;3&quot;&gt;Create a text file&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;touch &amp;lt;file&amp;gt;&lt;/td&gt;&lt;td&gt;create an empty file&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;vi &amp;lt;file&amp;gt;&lt;/td&gt;&lt;td&gt;use vi text editor to create a file (need to save the file though)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;echo &quot;foo&quot; &amp;gt;&amp;gt; &amp;lt;file&amp;gt;&lt;/td&gt;&lt;td&gt;create a file with content &#39;foo&#39;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;cat &amp;gt; &amp;lt;file&amp;gt;&lt;/td&gt;&lt;td&gt;enter multi-line texts and press &lt;b&gt;control-d&lt;/b&gt; to save the content to a file&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;3&quot;&gt;&lt;hr /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;3&quot;&gt;Change a file&#39;s modification or access time&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;stat &amp;lt;file1&amp;gt;&lt;/td&gt;&lt;td&gt;display the stat of given file&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;touch -m -d &#39;1 Mar 2013 02:53&#39; file.txt&lt;/td&gt;&lt;td&gt;change the modification time of file.txt to be &#39;1 Mar 2013 02:53&#39;, and create the file if it doesn&#39;t exist&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;touch -a -d &#39;1 Mar 2013 02:53&#39; file.txt&lt;/td&gt;&lt;td&gt;change the access time of file.txt to be &#39;1 Mar 2013 02:53&#39;, and create the file if it doesn&#39;t exist&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;3&quot;&gt;&lt;hr /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;3&quot;&gt;Compare two files&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;diff &amp;lt;file1&amp;gt; &amp;lt;file2&amp;gt;&lt;/td&gt;&lt;td&gt;show the differences between file1 and file2&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;sdiff &amp;lt;file1&amp;gt; &amp;lt;file2&amp;gt;&lt;/td&gt;&lt;td&gt;show file1 and file2 side by side&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;3&quot;&gt;&lt;hr /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;3&quot;&gt;Pipes and redirections&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;&amp;lt;command&amp;gt; &amp;gt; &amp;lt;file&amp;gt;&lt;/td&gt;&lt;td&gt;redirect command output to a file, e.g. ll &amp;gt; file.txt writes current directory listings to file.txt&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;&amp;lt;command&amp;gt; &amp;gt;&amp;gt; &amp;lt;file&amp;gt;&lt;/td&gt;&lt;td&gt;appends command output to the end of a file&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;&amp;lt;command&amp;gt; &amp;lt; &amp;lt;file&amp;gt;&lt;/td&gt;&lt;td&gt;redirect the standard input from the file&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;&amp;lt;command&amp;gt; &amp;lt; &amp;lt;file1&amp;gt; &amp;gt; &amp;lt;file2&amp;gt;&lt;/td&gt;&lt;td&gt;redirect the standard input from the file1, and then redirect the standard output to file2&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;&amp;lt;command1&amp;gt; | &amp;lt;command2&amp;gt;&lt;/td&gt;&lt;td&gt;pipe the output of command1 as the input of command2&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;3&quot;&gt;&lt;hr /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot;&gt;File permissions&lt;/td&gt;&lt;td&gt;read=4, write=2, execute=1&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;chmod 700 &amp;lt;file(s)&amp;gt;&lt;/td&gt;&lt;td&gt;file(s) owner can read, write and execute&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;chmod 600 &amp;lt;file(s)&amp;gt;&lt;/td&gt;&lt;td&gt;file(s) owner can read and write, but not execute&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;chmod 400 &amp;lt;file(s)&amp;gt;&lt;/td&gt;&lt;td&gt;file(s) owner can read only&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;chmod 755 &amp;lt;file(s)&amp;gt;&lt;/td&gt;&lt;td&gt;file(s) owner can read, write and execute; both group owner and others can read and write&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;chmod 644 &amp;lt;file(s)&amp;gt;&lt;/td&gt;&lt;td&gt;file(s) owner can read and write; both group owner and others can read only&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;chmod u+x &amp;lt;file(s)&amp;gt;&lt;/td&gt;&lt;td&gt;grant file(s) owner execute permission&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;chmod u-x &amp;lt;file(s)&amp;gt;&lt;/td&gt;&lt;td&gt;remove execute permission from file(s) owner&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;chmod a+rw &amp;lt;file(s)&amp;gt;&lt;/td&gt;&lt;td&gt;grant everyone read and write permission to the file(s)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;3&quot;&gt;&lt;hr /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot;&gt;Other useful comands&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;df -h&lt;/td&gt;&lt;td&gt;report file system disk space usage in human readable format&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;du -h&lt;/td&gt;&lt;td&gt;estimate file space usage in human readable format&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;date&lt;/td&gt;&lt;td&gt;display or set the current system date and time&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;top&lt;/td&gt;&lt;td&gt;display linux tasks, as well as CPU and memory stats&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;ps -aef&lt;/td&gt;&lt;td&gt;display a snapshot of current processes&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;ln -s &amp;lt;target&amp;gt; &amp;lt;link_name&amp;gt;&lt;/td&gt;&lt;td&gt;create a symbolic link to the target with link_name&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;alias&lt;/td&gt;&lt;td&gt;display current defined aliases or create an alias&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;50&quot;&gt;&lt;/td&gt;&lt;td width=&quot;200&quot;&gt;!&amp;lt;command&amp;gt;&lt;/td&gt;&lt;td&gt;invoke previous run of the given command&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
</content><link rel='replies' type='application/atom+xml' href='http://yongouyang.blogspot.com/feeds/577159155050511123/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://yongouyang.blogspot.com/2013/03/unix-cheat-sheet.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/577159155050511123'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/577159155050511123'/><link rel='alternate' type='text/html' href='http://yongouyang.blogspot.com/2013/03/unix-cheat-sheet.html' title='Unix Cheat Sheet'/><author><name>Yong Ouyang</name><uri>http://www.blogger.com/profile/05612250828808301428</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3705947190453566253.post-1064902012597460073</id><published>2013-03-20T13:31:00.002+08:00</published><updated>2013-03-20T13:32:57.624+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Availability"/><category scheme="http://www.blogger.com/atom/ns#" term="Object Modelling"/><category scheme="http://www.blogger.com/atom/ns#" term="Scalability"/><category scheme="http://www.blogger.com/atom/ns#" term="Software Development"/><category scheme="http://www.blogger.com/atom/ns#" term="testing"/><title type='text'>Most import aspects of software development</title><content type='html'>&lt;span style=&quot;font-family: Verdana, sans-serif;&quot;&gt;After a few years of software development, it is a good time to recap what are the most important aspects that I should be aware of when working any project. &lt;/span&gt;&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;&lt;span style=&quot;font-family: Verdana, sans-serif;&quot;&gt;The code base should be well tested that it has unit-tests, integration/acceptance-tests, external/smoke-tests. Unit test is about testing a single class by mocking its dependencies if necessary. Integration or acceptance tests should be testing the APIs provided by your application, particular front-to-back workflows, story-based features (as someone, I should be able to do something, etc.). External or smoke tests are verifying that the contracts between your application and your external dependencies are intact. There are a few reasons why automated tests are important:&lt;/span&gt;
&lt;ol type=&quot;a&quot;&gt;
&lt;li&gt;
&lt;span style=&quot;font-family: Verdana, sans-serif;&quot;&gt;developers have the confidence to refactor or make functional changes as they can run the automated tests to check whether there are any breaking changes&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: Verdana,sans-serif;&quot;&gt;no more painful and error prone manual tests conducted by the QA team -- cost savings, although UAT (User-Acceptance Test) is still required&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: Verdana,sans-serif;&quot;&gt;greatly shortens the release cycle because you spend a lot less time doing the manual tests&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;span style=&quot;font-family: Verdana,sans-serif;&quot;&gt;Modeling of the business objects is important because it &lt;/span&gt;&lt;span style=&quot;font-family: Verdana,sans-serif;&quot;&gt;&lt;span style=&quot;font-family: Verdana,sans-serif;&quot;&gt;not only &lt;/span&gt;affects how easy it is to query your business objects from the persistent layer, but also the performance of querying. One of the project that I worked on was storing a map of data into an oracle database as a CLOB data type (imagine a map is marshalled as XML string and stored as a DB column). It turned out to be rather inefficient to query any field inside that CLOB column, as you have to load the whole CLOB to your application!&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: Verdana,sans-serif;&quot;&gt;Availability and scalability are also crucial to any production system. Even Facebook does not guarantee that their query engine is available 100% of time (as they still have to do the manual failover of their name nodes, part of their &lt;a href=&quot;http://www.infoq.com/presentations/Hadoop-HDFS-Facebook&quot;&gt;Hadoop DFS cluster&lt;/a&gt;, from time to time). I won&#39;t treat Facebook as a mission critical application that has to be available all the time, but you can sense that to achieve a 100% availability, you will have to really think about your failover or DR (Disaster-Recovery) plan. Scalability is a tricky topic, as you can either scale horizontally by adding more nodes, or scale vertically by adding more cores/memories to the existing nodes (further reading on &lt;a href=&quot;http://en.wikipedia.org/wiki/Amdahl%27s_Law&quot;&gt;Amdahl&#39;s law&lt;/a&gt;). Depends on where the bottleneck of growth is, you might have database scalability, application scalability, caching scalability, etc. &lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
</content><link rel='replies' type='application/atom+xml' href='http://yongouyang.blogspot.com/feeds/1064902012597460073/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://yongouyang.blogspot.com/2013/03/most-import-aspects-of-software.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/1064902012597460073'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/1064902012597460073'/><link rel='alternate' type='text/html' href='http://yongouyang.blogspot.com/2013/03/most-import-aspects-of-software.html' title='Most import aspects of software development'/><author><name>Yong Ouyang</name><uri>http://www.blogger.com/profile/05612250828808301428</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3705947190453566253.post-4400768348741900509</id><published>2013-03-19T16:42:00.003+08:00</published><updated>2013-03-28T22:12:17.767+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Groovy"/><category scheme="http://www.blogger.com/atom/ns#" term="Java"/><category scheme="http://www.blogger.com/atom/ns#" term="Stack"/><title type='text'>An efficient Stack implementation with getMin() and getMax() methods</title><content type='html'>&lt;span style=&quot;font-family: Verdana, sans-serif;&quot;&gt;When we use stack to keep a collection of numbers, we might want to know what are the minimum and maximum numbers in the stack.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Verdana, sans-serif;&quot;&gt;Suppose we are pushing {72,12,55,78,22,34} into a stack, this is what happens&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;table borders=&quot;1&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;Stack Elements (Top ... Bottom)&lt;/th&gt;
&lt;th&gt;Min&lt;/th&gt;
&lt;th&gt;Max&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;push(72)&lt;/td&gt;&lt;td style=&quot;text-align: center;&quot;&gt;72&lt;/td&gt;&lt;td&gt;72&lt;/td&gt;&lt;td&gt;72&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;push(12)&lt;/td&gt;&lt;td style=&quot;text-align: center;&quot;&gt;12,72&lt;/td&gt;&lt;td&gt;12&lt;/td&gt;&lt;td&gt;72&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;push(55)&lt;/td&gt;&lt;td style=&quot;text-align: center;&quot;&gt;55,12,72&lt;/td&gt;&lt;td&gt;12&lt;/td&gt;&lt;td&gt;72&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;push(78)&lt;/td&gt;&lt;td style=&quot;text-align: center;&quot;&gt;78,55,12,72&lt;/td&gt;&lt;td&gt;12&lt;/td&gt;&lt;td&gt;78&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;push(22)&lt;/td&gt;&lt;td style=&quot;text-align: center;&quot;&gt;22,78,55,12,72&lt;/td&gt;&lt;td&gt;12&lt;/td&gt;&lt;td&gt;78&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;push(34)&lt;/td&gt;&lt;td style=&quot;text-align: center;&quot;&gt;34,22,78,55,12,72&lt;/td&gt;&lt;td&gt;12&lt;/td&gt;&lt;td&gt;78&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Verdana,sans-serif;&quot;&gt;If we pop the stack above 3 times, the max should change to 72; if we pop 2 more times, the min should change to 72. It sounds like we need a data structure that keeps the current min and max when we push or pop the stack. Indeed, a stack is a perfect choice here. When pushing a number to the stack, we also push the current min and max values into the min and max stacks respectively. Similarly, when poping out a number from the stack, we also pop out from the min and max stacks, such that the top of the min and max stacks will always have the min and max values of the current stack respectively.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Verdana,sans-serif;&quot;&gt;The complexity of the getMin() and getMax() methods are O(1), regardless of how many items are in the stack, same as the push(item) and pop() methods.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Verdana,sans-serif;&quot;&gt;Here is an implementation of the Stack with getMin() and getMax() methods&lt;/span&gt;

&lt;br /&gt;
&lt;pre&gt;import java.util.Stack;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class SmartStack&amp;lt;E extends Comparable&amp;lt;E&amp;gt;&amp;gt; {

    private ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    private ReentrantReadWriteLock.ReadLock readLock = readWriteLock.readLock();
    private ReentrantReadWriteLock.WriteLock writeLock = readWriteLock.writeLock();

    private Stack&amp;lt;E&amp;gt; mins = new Stack&amp;lt;E&amp;gt;();
    private Stack&amp;lt;E&amp;gt; maxs = new Stack&amp;lt;E&amp;gt;();
    private Stack&amp;lt;E&amp;gt; delegate = new Stack&amp;lt;E&amp;gt;();

    public E push(E item) {
        writeLock.lock();
        try {
            // stores the current min to the mins stack
            if (mins.isEmpty() || (!mins.isEmpty() &amp;amp;&amp;amp; item.compareTo(mins.peek()) &amp;lt; 0)) {
                mins.push(item);
            } else {
                mins.push(mins.peek());
            }

            // stores the current max to the maxs stack
            if (maxs.isEmpty() || (!maxs.isEmpty() &amp;amp;&amp;amp; item.compareTo(maxs.peek()) &amp;gt; 0)) {
                maxs.push(item);
            } else {
                maxs.push(maxs.peek());
            }

            return delegate.push(item);
        } finally {
            writeLock.unlock();
        }
    }

    public E pop() {
        writeLock.lock();
        try {
            E item = delegate.pop();
            // pop both mins and maxs stacks, such that peeking on them will tell us the current min or max
            mins.pop();
            maxs.pop();
            return item;
        } finally {
            writeLock.unlock();
        }
    }

    public E peek() {
        readLock.lock();
        try {
            return delegate.peek();
        } finally {
            readLock.unlock();
        }
    }

    public E getMin() {
        readLock.lock();
        try {
            return mins.peek();
        } finally {
            readLock.unlock();
        }
    }

    public E getMax() {
        readLock.lock();
        try {
            return maxs.peek();
        } finally {
            readLock.unlock();
        }
    }

    public boolean empty() {
        readLock.lock();
        try {
            return delegate.empty();
        } finally {
            readLock.unlock();
        }
    }

    public int search(E item) {
        readLock.lock();
        try {
            return delegate.search(item);
        } finally {
            readLock.unlock();
        }
    }
    
}&lt;/pre&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Verdana,sans-serif;&quot;&gt;Here is the unit test of the above class written in Groovy&lt;/span&gt;
&lt;br /&gt;
&lt;pre&gt;import org.junit.Before
import org.junit.Test

class SmartStackTest {

    SmartStack stack

    @Before
    public void before() {
        stack = new SmartStack()
        stack.push(72)
        stack.push(12)
        stack.push(55)
        stack.push(78)
        stack.push(22)
        stack.push(34)
    }

    @Test
    public void canGetCurrentMinValue() {
        assert stack.min == 12

        5.times { stack.pop() }

        assert stack.min == 72
    }

    @Test
    public void canGetCurrentMaxValue() {
        assert stack.max == 78

        4.times { stack.pop() }

        assert stack.max == 72
    }

    @Test
    public void canPeek() {
        assert stack.peek() == 34
    }

    @Test
    public void isEmpty() {
        assert !stack.empty()
    }

    @Test
    public void canSearch() {
        // the 1-based position from the top of the stack where the object is located
        assert stack.search(34) == 1
        assert stack.search(22) == 2
        assert stack.search(78) == 3
        assert stack.search(55) == 4
        assert stack.search(12) == 5
        assert stack.search(72) == 6
        // not in the stack should return -1
        assert stack.search(11112) == -1
    }
    
}
&lt;/pre&gt;
</content><link rel='replies' type='application/atom+xml' href='http://yongouyang.blogspot.com/feeds/4400768348741900509/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://yongouyang.blogspot.com/2013/03/an-efficient-stack-implementation-with.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/4400768348741900509'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/4400768348741900509'/><link rel='alternate' type='text/html' href='http://yongouyang.blogspot.com/2013/03/an-efficient-stack-implementation-with.html' title='An efficient Stack implementation with getMin() and getMax() methods'/><author><name>Yong Ouyang</name><uri>http://www.blogger.com/profile/05612250828808301428</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3705947190453566253.post-7054712486160815282</id><published>2013-03-19T14:10:00.000+08:00</published><updated>2013-03-28T22:12:35.687+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Directed Graphs"/><category scheme="http://www.blogger.com/atom/ns#" term="Graphs"/><category scheme="http://www.blogger.com/atom/ns#" term="Sorting"/><category scheme="http://www.blogger.com/atom/ns#" term="Topological Sort"/><title type='text'>Sorting objects with one-way dependency using Topological Sort with Directed Graphs</title><content type='html'>&lt;span style=&quot;font-family: Verdana, sans-serif;&quot;&gt;Suppose there are a bunch of objects to be evaluated, each of which might depend on a number of other objects being evaluated first before it can be evaluated. The objects being depended on might depend on other objects. There is no cyclic dependency that object A depends on object B, and object B depends on object C, and object C depends on object A.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Verdana, sans-serif;&quot;&gt;To solve this problem, we want to sort these objects such that when traversing through these objects, they should be ready for evaluation and their dependencies, if applicable, should have been evaluated. The &lt;/span&gt;&lt;span style=&quot;font-family: Verdana, sans-serif;&quot;&gt;&lt;span style=&quot;font-family: Verdana, sans-serif;&quot;&gt;sorting algorithm and&lt;/span&gt; data structure that are applicable for this problem is Topological Sort with Directed Graphs.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Verdana, sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgox6L81p2zYDEPDz0l5sjtTILAeF2elh-SQmjDbMtKF_RvxG7lMn4Qw6pwSbpgqQRxfMtpiGgmRw1UrXmeA97VxPsRAJXsUSeq1vJPiq8gYnm_ae04-YiAy-dmzBUxIo3pU_i0hYgqiVtg/s1600/Drawing2.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgox6L81p2zYDEPDz0l5sjtTILAeF2elh-SQmjDbMtKF_RvxG7lMn4Qw6pwSbpgqQRxfMtpiGgmRw1UrXmeA97VxPsRAJXsUSeq1vJPiq8gYnm_ae04-YiAy-dmzBUxIo3pU_i0hYgqiVtg/s1600/Drawing2.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;span style=&quot;font-family: Verdana, sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Verdana, sans-serif;&quot;&gt;If the edges in a graph have a direction, the graph is called a directed graph, as shown above. The arrows in the figure show the direction of the edges. We also include two vertices here to represent isolated objects that don&#39;t depend on other objects.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Verdana,sans-serif;&quot;&gt;The arrows in the figure represent evaluation direction. For example, to evaluate E, we must first evaluate A and B. To evaluate H, we might want a sorted collection like this:&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Verdana,sans-serif;&quot;&gt;ADBECFDGH or ADGBECFH&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Verdana,sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Verdana,sans-serif;&quot;&gt;There are many other possible ordering, depending on the approach you take to implement the topological sort.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Verdana,sans-serif;&quot;&gt;DirectedGraph.java&lt;/span&gt; &lt;br /&gt;
&lt;pre&gt;import java.util.*;

public class DirectedGraph&amp;lt;T&amp;gt; implements Iterable&amp;lt;T&amp;gt; {

    // key is a Node, value is a set of Nodes connected by outgoing edges from the key
    private final Map&amp;lt;T, Set&amp;lt;T&amp;gt;&amp;gt; graph = new HashMap&amp;lt;T, Set&amp;lt;T&amp;gt;&amp;gt;();

    public boolean addNode(T node) {
        if (graph.containsKey(node)) {
            return false;
        }

        graph.put(node, new HashSet&amp;lt;T&amp;gt;());
        return true;
    }

    public void addNodes(Collection&amp;lt;T&amp;gt; nodes) {
        for (T node : nodes) {
            addNode(node);
        }
    }

    public void addEdge(T src, T dest) {
        validateSourceAndDestinationNodes(src, dest);

        // Add the edge by adding the dest node into the outgoing edges
        graph.get(src).add(dest);
    }

    public void removeEdge(T src, T dest) {
        validateSourceAndDestinationNodes(src, dest);

        graph.get(src).remove(dest);
    }

    public boolean edgeExists(T src, T dest) {
        validateSourceAndDestinationNodes(src, dest);

        return graph.get(src).contains(dest);
    }

    public Set&amp;lt;T&amp;gt; edgesFrom(T node) {
        // Check that the node exists.
        Set&amp;lt;T&amp;gt; edges = graph.get(node);
        if (edges == null)
            throw new NoSuchElementException(&quot;Source node does not exist.&quot;);

        return Collections.unmodifiableSet(edges);
    }

    public Iterator&amp;lt;T&amp;gt; iterator() {
        return graph.keySet().iterator();
    }

    public int size() {
        return graph.size();
    }

    public boolean isEmpty() {
        return graph.isEmpty();
    }

    private void validateSourceAndDestinationNodes(T src, T dest) {
        // Confirm both endpoints exist
        if (!graph.containsKey(src) || !graph.containsKey(dest))
            throw new NoSuchElementException(&quot;Both nodes must be in the graph.&quot;);
    }

}&lt;t&gt;&lt;t&gt;&lt;t set=&quot;&quot;&gt;&lt;t set=&quot;&quot;&gt;&lt;t&gt;&lt;t&gt;&lt;t&gt;&lt;t&gt;&lt;t&gt;
&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Verdana,sans-serif;&quot;&gt;TolopogicalSort.java&lt;/span&gt;
&lt;br /&gt;
&lt;pre&gt;import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class TopologicalSort {

    public static &amp;lt;T&amp;gt; List&amp;lt;T&amp;gt; sort(DirectedGraph&amp;lt;T&amp;gt; graph) {
        DirectedGraph&amp;lt;T&amp;gt; reversedGraph = reverseGraph(graph);

        List&amp;lt;T&amp;gt; result = new ArrayList&amp;lt;T&amp;gt;();
        Set&amp;lt;T&amp;gt; visited = new HashSet&amp;lt;T&amp;gt;();

        /* We&#39;ll also maintain a third set consisting of all nodes that have
         * been fully expanded.  If the graph contains a cycle, then we can
         * detect this by noting that a node has been explored but not fully
         * expanded.
         */
        Set&amp;lt;T&amp;gt; expanded = new HashSet&amp;lt;T&amp;gt;();

        // Fire off a Depth-First Search from each node in the graph
        for (T node : reversedGraph)
            explore(node, reversedGraph, result, visited, expanded);

        return result;
    }


    /**
     * Recursively performs a Depth-First Search from the specified node, marking all nodes
     * encountered by the search.
     *
     * @param node     The node to begin the search from.
     * @param graph    The graph in which to perform the search.
     * @param result   A list holding the topological sort of the graph.
     * @param visited  A set of nodes that have already been visited.
     * @param expanded A set of nodes that have been fully expanded.
     */
    private static &amp;lt;T&amp;gt; void explore(T node, DirectedGraph&amp;lt;T&amp;gt; graph, List&amp;lt;T&amp;gt; result, Set&amp;lt;T&amp;gt; visited, Set&amp;lt;T&amp;gt; expanded) {
        if (visited.contains(node)) {
            // if this node has already been expanded, then it&#39;s already been assigned a
            // position in the final topological sort and we don&#39;t need to explore it again.
            if (expanded.contains(node)) return;

            // if it hasn&#39;t been expanded, it means that we&#39;ve just found a node that is currently being explored,
            // and therefore is part of a cycle.  In that case, we should report an error.
            throw new IllegalArgumentException(&quot;A cycle was detected within the Graph when exploring node &quot; + node.toString());
        }

        visited.add(node);

        // recursively explore all predecessors of this node
        for (T predecessor : graph.edgesFrom(node))
            explore(predecessor, graph, result, visited, expanded);

        result.add(node);
        expanded.add(node);
    }

    private static &amp;lt;T&amp;gt; DirectedGraph&amp;lt;T&amp;gt; reverseGraph(DirectedGraph&amp;lt;T&amp;gt; graph) {
        DirectedGraph&amp;lt;T&amp;gt; result = new DirectedGraph&amp;lt;T&amp;gt;();

        // Add all the nodes from the original graph
        for (T node : graph) {
            result.addNode(node);
        }

        // Scan over all the edges in the graph, adding their reverse to the reverse graph.
        for (T node : graph) {
            for (T endpoint : graph.edgesFrom(node)) {
                result.addEdge(endpoint, node);
            }
        }

        return result;
    }

}&lt;t&gt;&lt;t&gt;&lt;t&gt;&lt;t&gt;&lt;t&gt;&lt;t&gt;&lt;t&gt;&lt;t&gt;&lt;t&gt;&lt;t&gt;&lt;t&gt;&lt;t&gt;&lt;t&gt;&lt;t&gt;&lt;t&gt;&lt;t&gt;&lt;t&gt;&lt;t&gt;&lt;t&gt;&lt;t&gt;
&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Verdana,sans-serif;&quot;&gt;Below demonstrate the setup of the directed graph and will print out the sorted result.
&lt;/span&gt;&lt;br /&gt;
&lt;pre&gt;    public static void main(String[] args) {
        DirectedGraph&lt;string&gt; graph = new DirectedGraph&lt;string&gt;()
        graph.addNode(&quot;A&quot;);
        graph.addNode(&quot;B&quot;);
        graph.addNode(&quot;C&quot;);
        graph.addNode(&quot;D&quot;);
        graph.addNode(&quot;E&quot;);
        graph.addNode(&quot;F&quot;);
        graph.addNode(&quot;G&quot;);
        graph.addNode(&quot;H&quot;);
        graph.addNode(&quot;I&quot;);
        graph.addNode(&quot;J&quot;);

        graph.addEdge(&quot;A&quot;, &quot;D&quot;);
        graph.addEdge(&quot;A&quot;, &quot;E&quot;);
        graph.addEdge(&quot;B&quot;, &quot;E&quot;);
        graph.addEdge(&quot;C&quot;, &quot;F&quot;);
        graph.addEdge(&quot;D&quot;, &quot;G&quot;);
        graph.addEdge(&quot;E&quot;, &quot;H&quot;);
        graph.addEdge(&quot;F&quot;, &quot;H&quot;);
        graph.addEdge(&quot;G&quot;, &quot;H&quot;);

        List&lt;string&gt; sorted = TopologicalSort.sort(graph)

        System.out.println(sorted)
    }
&lt;/string&gt;&lt;/string&gt;&lt;/string&gt;&lt;/pre&gt;
</content><link rel='replies' type='application/atom+xml' href='http://yongouyang.blogspot.com/feeds/7054712486160815282/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://yongouyang.blogspot.com/2013/03/sorting-objects-with-one-way-dependency.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/7054712486160815282'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/7054712486160815282'/><link rel='alternate' type='text/html' href='http://yongouyang.blogspot.com/2013/03/sorting-objects-with-one-way-dependency.html' title='Sorting objects with one-way dependency using Topological Sort with Directed Graphs'/><author><name>Yong Ouyang</name><uri>http://www.blogger.com/profile/05612250828808301428</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgox6L81p2zYDEPDz0l5sjtTILAeF2elh-SQmjDbMtKF_RvxG7lMn4Qw6pwSbpgqQRxfMtpiGgmRw1UrXmeA97VxPsRAJXsUSeq1vJPiq8gYnm_ae04-YiAy-dmzBUxIo3pU_i0hYgqiVtg/s72-c/Drawing2.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3705947190453566253.post-87273487444528899</id><published>2013-03-19T12:21:00.003+08:00</published><updated>2013-03-28T22:12:51.283+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Merge Sort"/><category scheme="http://www.blogger.com/atom/ns#" term="Sorting"/><title type='text'>Merge Sort in Java</title><content type='html'>&lt;span style=&quot;font-family: Verdana, sans-serif;&quot;&gt;The merge sort is a much more efficient sorting algorithm than those simple ones, for example, bubble sort, selection sort, and &lt;/span&gt;&lt;span style=&quot;font-family: Verdana, sans-serif;&quot;&gt;insertion sort. While the simple sorting algorithms have O(N&lt;sup&gt;2&lt;/sup&gt;) complexity, the merge sort is O(N*logN).&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Verdana, sans-serif;&quot;&gt;The merge sort routine tries to break down an array into 2 sub-arrays, sort these sub-arrays, and merge them back, in a recursive way, as you shall see in the implementation below, as well as the graph below.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Verdana, sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEia6W-lC8fTOvshWRtnvBNSFngjuxv9l7aBg8a2KeBjh7pFMZGMGqCTDwVnaxHp4KmN6L38SLZ1fgesGPN6AAXatwtzI2zD1_xSfIWU8FYBihIOvY6WH163oLQgFzX0B_gCXJXeoYOi-UIb/s1600/Drawing1.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEia6W-lC8fTOvshWRtnvBNSFngjuxv9l7aBg8a2KeBjh7pFMZGMGqCTDwVnaxHp4KmN6L38SLZ1fgesGPN6AAXatwtzI2zD1_xSfIWU8FYBihIOvY6WH163oLQgFzX0B_gCXJXeoYOi-UIb/s1600/Drawing1.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;span style=&quot;font-family: Verdana, sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Verdana, sans-serif;&quot;&gt;&amp;nbsp;&lt;/span&gt;

&lt;br /&gt;
&lt;pre&gt;import java.util.Arrays;
import java.util.Random;

public class MergeSortTest {

    static int numberOfElements = 10;
    static int maxValue = 100;

    public static void main(String[] args) {
        int[] original = createArrayWithRandomValues();
        // workspace array is used to keep the partial sorted results
        int[] workspace = new int[original.length];
        mergeSort(original, workspace, 0, numberOfElements - 1);

        System.out.println(&quot;The sorted array is &quot; + Arrays.toString(original));
    }

    private static int[] createArrayWithRandomValues() {
        Random random = new Random();
        int[] original = new int[numberOfElements];
        for (int i = 0; i &amp;lt; numberOfElements; i++) {
            original[i] = random.nextInt(maxValue);
        }
        System.out.println(&quot;The original array is &quot; + Arrays.toString(original));
        return original;
    }

    private static void mergeSort(int[] original, int[] workSpace, int lowerBound, int upperBound) {
        if (lowerBound != upperBound) {
            // find midpoint
            int mid = (lowerBound + upperBound) / 2;
            // sort lower half
            mergeSort(original, workSpace, lowerBound, mid);
            // sort upper half
            mergeSort(original, workSpace, mid + 1, upperBound);
            // merge them
            merge(original, workSpace, lowerBound, mid, upperBound);
        }
    }

    private static void merge(int[] original, int[] workSpace, int lowerBound, int middle, int upperBound) {
        // Copy both parts into the workspace array
        System.arraycopy(original, lowerBound, workSpace, lowerBound, upperBound + 1 - lowerBound);

        int leftPointer = lowerBound;
        int rightPointer = middle + 1;
        int originalPointer = lowerBound;

        // Copy the smallest values from either the left or the right side back to the original array
        while (leftPointer &amp;lt;= middle &amp;amp;&amp;amp; rightPointer &amp;lt;= upperBound) {
            if (workSpace[leftPointer] &amp;lt;= workSpace[rightPointer]) {
                // copy and move the pointer on workspace to the next smallest value on left (if there is any)
                original[originalPointer++] = workSpace[leftPointer++];
            } else {
                // copy and move the pointer on workspace to the next smallest value on right (if there is any)
                original[originalPointer++] = workSpace[rightPointer++];
            }
        }
        // Copy the rest of the left side of the array into the target array
        while (leftPointer &amp;lt;= middle) {
            original[originalPointer++] = workSpace[leftPointer++];
        }

        // if there are elements left in the right side of the workspace, those
        // are the largest values of the merged array, so no action is required
    }
    
}
&lt;/pre&gt;
</content><link rel='replies' type='application/atom+xml' href='http://yongouyang.blogspot.com/feeds/87273487444528899/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://yongouyang.blogspot.com/2013/03/merge-sort-in-java.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/87273487444528899'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/87273487444528899'/><link rel='alternate' type='text/html' href='http://yongouyang.blogspot.com/2013/03/merge-sort-in-java.html' title='Merge Sort in Java'/><author><name>Yong Ouyang</name><uri>http://www.blogger.com/profile/05612250828808301428</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEia6W-lC8fTOvshWRtnvBNSFngjuxv9l7aBg8a2KeBjh7pFMZGMGqCTDwVnaxHp4KmN6L38SLZ1fgesGPN6AAXatwtzI2zD1_xSfIWU8FYBihIOvY6WH163oLQgFzX0B_gCXJXeoYOi-UIb/s72-c/Drawing1.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3705947190453566253.post-1432130420863913334</id><published>2013-03-18T23:28:00.001+08:00</published><updated>2013-03-28T22:13:08.492+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Insertion Sort"/><category scheme="http://www.blogger.com/atom/ns#" term="Sorting"/><title type='text'>Insertion Sort in Java</title><content type='html'>&lt;span style=&quot;font-family: Verdana,sans-serif;&quot;&gt;Insertion sort is about twice as fast as the bubble sort, and faster than selection sort.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Verdana,sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Verdana,sans-serif;&quot;&gt;In an insertion sort routine, we will pick a marker (starting from index=1), store the marked number, and compare the marked number with its neighbours on the left. Shift all the neighbours, which are larger than the marked number, one position to the right. After the shift, insert the marked number to the empty slot. Repeat this procedure until the marker index points to the last number on the right.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Verdana,sans-serif;&quot;&gt;Below demonstrates one of the implementations of the insertion sort algorithm. &lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;import java.util.Arrays;
import java.util.Random;

public class InsertionSortTest {

    static int numberOfElements = 10;
    static int maxValue = 100;

    public static void main(String[] args) {
        int[] original = createArrayWithRandomValues();

        insertionSort(original);

        System.out.println(&quot;The sorted array is &quot; + Arrays.toString(original));
    }

    private static int[] createArrayWithRandomValues() {
        Random random = new Random();
        int[] original = new int[numberOfElements];
        for (int i = 0; i &amp;lt; numberOfElements; i++) {
            original[i] = random.nextInt(maxValue);
        }
        System.out.println(&quot;The original array is &quot; + Arrays.toString(original));
        return original;
    }

    private static void insertionSort(int[] original) {
        int markerIndex, emptySlotIndex;
        for (markerIndex = 1; markerIndex &amp;lt; original.length; markerIndex++) {
            int marked = original[markerIndex]; // use a temp variable to store the marked number
            emptySlotIndex = markerIndex;
            while (emptySlotIndex &amp;gt; 0 &amp;amp;&amp;amp; original[emptySlotIndex - 1] &amp;gt;= marked) {
                original[emptySlotIndex] = original[emptySlotIndex - 1]; // shift element right
                emptySlotIndex--; // moves the empty slot index one position to the left
            }
            original[emptySlotIndex] = marked; // insert marked element
        }
    }
    
}
&lt;/pre&gt;
</content><link rel='replies' type='application/atom+xml' href='http://yongouyang.blogspot.com/feeds/1432130420863913334/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://yongouyang.blogspot.com/2013/03/insertion-sort-in-java.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/1432130420863913334'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/1432130420863913334'/><link rel='alternate' type='text/html' href='http://yongouyang.blogspot.com/2013/03/insertion-sort-in-java.html' title='Insertion Sort in Java'/><author><name>Yong Ouyang</name><uri>http://www.blogger.com/profile/05612250828808301428</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3705947190453566253.post-52308343928929161</id><published>2013-03-18T19:12:00.003+08:00</published><updated>2013-03-28T22:13:39.513+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Selection Sort"/><category scheme="http://www.blogger.com/atom/ns#" term="Sorting"/><title type='text'>Selection Sort in Java</title><content type='html'>&lt;span style=&quot;font-family: Verdana, sans-serif;&quot;&gt;Selection sort is slightly faster than bubble sort because the number of required swaps is reduced from O(N&lt;sup&gt;2&lt;/sup&gt;) to O(N), while the number of comparisons remains O(N&lt;sup&gt;2&lt;/sup&gt;).&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Verdana,sans-serif;&quot;&gt;Below demonstrates one of the implementations of the selection sort algorithm. &lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Verdana, sans-serif;&quot;&gt;&amp;nbsp;&lt;/span&gt;

&lt;br /&gt;
&lt;pre&gt;import java.util.Arrays;
import java.util.Random;

public class SelectionSortTest {

    static int numberOfElements = 10;
    static int maxValue = 100;

    public static void main(String[] args) {
        int[] original = createArrayWithRandomValues();

        selectionSort(original);

        System.out.println(&quot;The sorted array is &quot; + Arrays.toString(original));
    }

    private static int[] createArrayWithRandomValues() {
        Random random = new Random();
        int[] original = new int[numberOfElements];
        for (int start = 1; start &amp;lt;= numberOfElements; start++) {
            original[start - 1] = random.nextInt(maxValue);
        }
        System.out.println(&quot;The original array is &quot; + Arrays.toString(original));
        return original;
    }


    private static void selectionSort(int[] original) {
        int outer, inner, minIndex;
        for (outer = 0; outer &amp;lt; original.length - 1; outer++) { // from 1st element to next-to-last element
            minIndex = outer; // each round the min index starts from the outer index
            for (inner = outer + 1; inner &amp;lt; original.length; inner++) { // from outer + 1 element to the last element
                if (original[inner] &amp;lt; original[minIndex]) { // remember the index for the new minimum
                    minIndex = inner;
                }
            }

            // swap the elements between outer index and min index
            int temp = original[outer];
            original[outer] = original[minIndex];
            original[minIndex] = temp;

        }
    }
    
}
&lt;/pre&gt;
</content><link rel='replies' type='application/atom+xml' href='http://yongouyang.blogspot.com/feeds/52308343928929161/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://yongouyang.blogspot.com/2013/03/selection-sort-in-java.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/52308343928929161'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/52308343928929161'/><link rel='alternate' type='text/html' href='http://yongouyang.blogspot.com/2013/03/selection-sort-in-java.html' title='Selection Sort in Java'/><author><name>Yong Ouyang</name><uri>http://www.blogger.com/profile/05612250828808301428</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3705947190453566253.post-4131069426189690058</id><published>2013-03-18T15:48:00.000+08:00</published><updated>2013-03-28T22:14:00.745+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Bubble Sort"/><category scheme="http://www.blogger.com/atom/ns#" term="Sorting"/><title type='text'>Bubble Sort in Java</title><content type='html'>&lt;span style=&quot;font-family: Verdana,sans-serif;&quot;&gt;&lt;span style=&quot;font-family: Verdana,sans-serif;&quot;&gt;Given an array of n (n&amp;gt;1) 
numbers, we want to sort them such that the smallest number is on the 
left, and the largest number is on the right. This is where all the sorting fun comes from.&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Verdana,sans-serif;&quot;&gt;Bubble sort is one of the slowest of all sorting algorithms, but it is conceptually the simplest.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Verdana,sans-serif;&quot;&gt;In bubble sort routine, we start by comparing two numbers in the array, say the 1st (array[0]) and 2nd (array[1]) numbers. If the 1st number is larger than the 2nd number, we swap them, otherwise don&#39;t do anything. Then we move over one position and compare the 2nd and 3rd numbers, and so on, until we&#39;ve completed the comparison of the second last and the last number. At this point, the largest number has been bubbled up all the way to the right (array[n-1]). On the 2nd round, we only need to do the comparison and swap from array[0] to array[n-2], which will ensure array[n-2] has the 2nd largest value in the array. Continue like this until the (n-1)th round.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Verdana,sans-serif;&quot;&gt;The algorithm complexity, when expressed in Big O notation, is O(N&lt;sup&gt;2&lt;/sup&gt;). This is because, given an array of 10 numbers, you will need 9 comparisons on the first round to bubble the largest number to the right, and 8 comparisons on the second round, and so on, while the last round requires 1 comparison. That is&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Verdana,sans-serif;&quot;&gt;9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 = 45, or n*(n-1)/2,&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Verdana,sans-serif;&quot;&gt;where n is the number of elements in the array. On the other hand, a swap is only required when the number on the left is larger than the one on the right, although in the worst case scenario, when the initial array is sorted such that the largest number is on the left and the smallest number is on the right, a swap is necessary for every comparison. Therefore, the number of swaps and comparisons are proportional to n&lt;sup&gt;2&lt;/sup&gt;.This is how we work out bubble sort&#39;s complexity &lt;/span&gt;&lt;span style=&quot;font-family: Verdana,sans-serif;&quot;&gt;O(N&lt;sup&gt;2&lt;/sup&gt;).&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Verdana,sans-serif;&quot;&gt;Below demonstrates one of the implementations of the bubble sort algorithm. &lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;import java.util.Arrays;
import java.util.Random;

public class BubbleSortTest {

    static int numberOfElements = 10;
    static int maxValue = 100;

    public static void main(String[] args) {
        int[] original = createArrayWithRandomValues();

        bubbleSort(original);

        System.out.println(&quot;The sorted array is &quot; + Arrays.toString(original));
    }

    private static int[] createArrayWithRandomValues() {
        Random random = new Random();
        int[] original = new int[numberOfElements];
        for (int start = 1; start &amp;lt;= numberOfElements; start++) {
            original[start - 1] = random.nextInt(maxValue);
        }
        System.out.println(&quot;The original array is &quot; + Arrays.toString(original));
        return original;
    }

    private static void bubbleSort(int[] original) {
        int outer, inner;
        for (outer = original.length - 1; outer &amp;gt; 1; outer--) { // from last element to the 2nd element
            for (inner = 0; inner &amp;lt; outer; inner++) { // from the 1st element to outer index - 1
                if (original[inner] &amp;gt; original[inner + 1]) { // bubble up the bigger value to the right
                    int temp = original[inner];
                    original[inner] = original[inner + 1];
                    original[inner + 1] = temp;
                }
            }
        }
    }

}
&lt;/pre&gt;
</content><link rel='replies' type='application/atom+xml' href='http://yongouyang.blogspot.com/feeds/4131069426189690058/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://yongouyang.blogspot.com/2013/03/bubble-sort-with-sample.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/4131069426189690058'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/4131069426189690058'/><link rel='alternate' type='text/html' href='http://yongouyang.blogspot.com/2013/03/bubble-sort-with-sample.html' title='Bubble Sort in Java'/><author><name>Yong Ouyang</name><uri>http://www.blogger.com/profile/05612250828808301428</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3705947190453566253.post-3307584612871893106</id><published>2011-06-28T22:55:00.001+08:00</published><updated>2011-06-28T22:56:38.518+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Ant"/><category scheme="http://www.blogger.com/atom/ns#" term="junit"/><category scheme="http://www.blogger.com/atom/ns#" term="Teamcity"/><category scheme="http://www.blogger.com/atom/ns#" term="testing"/><title type='text'>Show @Ignored junit 4 tests in XML output on teamcity</title><content type='html'>Not long ago, I managed to migrate tests to junit 4. But when I ran the tests remotely on Teamcity build server (my project is using Ant as runner on Teamcity), the report didn&#39;t show any ignored tests that were marked @Ignore. &lt;br /&gt;
&lt;br /&gt;
I was shocked to discover that this issue was first reported a few years ago here &lt;a href=&quot;https://issues.apache.org/bugzilla/show_bug.cgi?id=43969&quot;&gt;&lt;/a&gt; , and it is still uncertain when Ant will fix it. Fortunately, &lt;a href=&quot;http://code.google.com/p/reporting-junit-runner/&quot;&gt;&lt;/a&gt; is the one that saves my purposes of migrating all the tests into junit 4.&lt;br /&gt;
&lt;br /&gt;
Here is an example of how we can create a suite runner to run multiple tests or test suites. The purpose of this suite runner is to generate xml-based test reports that will be stored onto specified folder such that Teamcity can then import these report data from &quot;Ant JUnit&quot; format from the specified folder.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;public class SomeSuiteRunner {
    
    public static void main() throws Exception {
        boolean success = new SomeSuiteRunner().run();
        System.exit(success ? 0 : 1);
    }

    public boolean run() throws Exception {    
        File reportDirectory = new File(&quot;/reports&quot;);
        org.apache.commons.io.FileUtils.deleteDirectory(reportDirectory); 
        reportDirectory.mkdirs();
        return runTests();
    }

    private boolean runTests() throws Exception {
        boolean isSuccessful = true;
        final Class testClass =  this.getClass().getClassLoader().loadClass(&quot;package.ATest&quot;);
        return runTestClass(testClass);
    }

    private boolean runTestClass(Class testClass) {
        JUnitCore runner = new JUnitCore();
        final XmlWritingListener listener = new XmlWritingListener(&quot;/reports&quot;);
        runner.addListener(listener);
        listener.startFile(testClass);
        try{
           return runner.run(testClass);
        } finally {
           listener.closeFile();
        }
    }
    
}
&lt;/pre&gt;&lt;br /&gt;
To be able to show the number of @Ignore tests on Teamcity, we need to config our project on Teamcity properly (in &quot;Runner&quot; settings):&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;choose an appropriate &quot;Build runner&quot;&lt;/li&gt;
&lt;li&gt;choose &quot;Ant JUnit&quot; as the &quot;Import data from XML&quot;&lt;/li&gt;
&lt;li&gt;tpye, for example, &quot;/reports/*.xml&quot; in the &quot;Report paths&quot; &lt;/li&gt;
&lt;/ol&gt;</content><link rel='replies' type='application/atom+xml' href='http://yongouyang.blogspot.com/feeds/3307584612871893106/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://yongouyang.blogspot.com/2011/06/show-ignored-junit-4-tests-in-xml.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/3307584612871893106'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/3307584612871893106'/><link rel='alternate' type='text/html' href='http://yongouyang.blogspot.com/2011/06/show-ignored-junit-4-tests-in-xml.html' title='Show @Ignored junit 4 tests in XML output on teamcity'/><author><name>Yong Ouyang</name><uri>http://www.blogger.com/profile/05612250828808301428</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3705947190453566253.post-8942917952481900668</id><published>2011-06-27T06:41:00.003+08:00</published><updated>2011-06-28T21:18:37.493+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="junit"/><category scheme="http://www.blogger.com/atom/ns#" term="testing"/><title type='text'>Migrating tests from junit 3 to junit 4</title><content type='html'>&lt;div&gt;For some legacy reason, the project that I am working on has been using junit 3 for all the unit and integration tests since day 1. Last week, I decided to do something different that could cheer up my mind and a step forward to more flexibilities in testing.&lt;br /&gt;
&lt;br /&gt;
It could be an relative easy task, but it turned out to cost me a whole day to complete the migration of 700+ test classes.&lt;br /&gt;
&lt;br /&gt;
1) Based on the suggestions on &lt;a href=&quot;http://stackoverflow.com/questions/264680/best-way-to-automagically-migrate-tests-from-junit-3-to-junit-4&quot;&gt;http://stackoverflow.com/questions/264680/best-way-to-automagically-migrate-tests-from-junit-3-to-junit-4&lt;/a&gt; , I performed the initial easy-task by the following regular expressions:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;// Add @Test&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;Replace&lt;/span&gt;:&lt;br /&gt;
^[ \t] +((publicpublic abstract) +void +test)&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;With&lt;/span&gt;:&lt;br /&gt;
@Test\n    $1&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;Regular Expression&lt;/span&gt;: on&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;Case sensitive&lt;/span&gt;: on&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;File name filter&lt;/span&gt;: *Test.java, *TestCase.java&lt;br /&gt;
&lt;br /&gt;
// Remove double @Test&#39;s on already @Test annotated files&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;Replace&lt;/span&gt;:&lt;br /&gt;
^[ \t]+@Test\n[ \t]+@Test&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;With&lt;/span&gt;:&lt;br /&gt;
@Test&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;Regular Expression&lt;/span&gt;: on&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;Case sensitive&lt;/span&gt;: on&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;File name filter&lt;/span&gt;:&lt;br /&gt;
*Test.java, *TestCase.java&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// Remove all empty setUp&#39;s&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;Replace&lt;/span&gt;:&lt;br /&gt;
^[ \*]+((publicprotected) +)?void +setUp\(\)[^\{]*\{\s*(super\.setUp\(\);)?\s*\}\n([ \t]*\n)?&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;With&lt;/span&gt;: nothing&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;Regular Expression&lt;/span&gt;: on&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;Case sensitive&lt;/span&gt;: on&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;File name filter&lt;/span&gt;:&lt;br /&gt;
*Test.java, *TestCase.java&lt;br /&gt;
&lt;br /&gt;
// Add @Before to all setUp&#39;s&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;Replace&lt;/span&gt;:&lt;br /&gt;
^([ \t]+@Override\n)?[ \t]+((publicprotected) +)?(void +setUp\(\))&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;With&lt;/span&gt;:&lt;br /&gt;
@Before\n    public void setUp()&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;Regular Expression&lt;/span&gt;: on&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;Case sensitive&lt;/span&gt;: on&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;File name filter&lt;/span&gt;:&lt;br /&gt;
*Test.java, *TestCase.java&lt;br /&gt;
&lt;br /&gt;
// Remove double @Before&#39;s on already @Before annotated files&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;Replace&lt;/span&gt;:&lt;br /&gt;
^[ \t]+@Before\n[ \t]+@Before&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;With&lt;/span&gt;:&lt;br /&gt;
@Before&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;Regular Expression&lt;/span&gt;: on&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;Case sensitive&lt;/span&gt;: on&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;File name filter&lt;/span&gt;:&lt;br /&gt;
*Test.java, *TestCase.java&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// Remove all empty tearDown&#39;s&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;Replace&lt;/span&gt;:&lt;br /&gt;
^[ \*]+((publicprotected) +)?void +tearDown\(\)[^\{]*\{\s*(super\.tearDown\(\);)?\s*\}\n([ \t]*\n)?&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;With&lt;/span&gt;: nothing&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;Regular Expression&lt;/span&gt;: on&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;Case sensitive&lt;/span&gt;: on&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;File name filter&lt;/span&gt;:&lt;br /&gt;
*Test.java, *TestCase.java&lt;br /&gt;
&lt;br /&gt;
// Add @After to all tearDown&#39;s&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;Replace&lt;/span&gt;:&lt;br /&gt;
^([ \t]+@Override\n)?[ \t]+((publicprotected) +)?(void +tearDown\(\))&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;With&lt;/span&gt;:&lt;br /&gt;
@After\n    public void tearDown()&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;Regular Expression&lt;/span&gt;: on&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;Case sensitive&lt;/span&gt;: on&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;File name filter&lt;/span&gt;:&lt;br /&gt;
*Test.java, *TestCase.java&lt;br /&gt;
&lt;br /&gt;
// Remove double @After&#39;s on already @After annotated files&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;Replace&lt;/span&gt;:&lt;br /&gt;
^[ \t]+@After\n[ \t]+@After&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;With&lt;/span&gt;:&lt;br /&gt;
@After&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;Regular Expression&lt;/span&gt;: on&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;Case sensitive&lt;/span&gt;: on&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;File name filter&lt;/span&gt;:&lt;br /&gt;
*Test.java, *TestCase.java&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// Remove old imports, add new imports&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;Replace&lt;/span&gt;:&lt;br /&gt;
^([ \t]*import[ \t]+junit\.framework\.Assert;\n)?[ \t]*import[ \t]+junit\.framework\.TestCase;&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;With&lt;/span&gt;:&lt;br /&gt;
import org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport static org.junit.Assert.*;&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;Regular Expression&lt;/span&gt;: on&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;Case sensitive&lt;/span&gt;: on&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;File name filter&lt;/span&gt;:&lt;br /&gt;
*Test.java, *TestCase.java&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// Remove all extends TestCase&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;Replace&lt;/span&gt;:&lt;br /&gt;
[ \t]+extends[ \t]+(TestCase)[ \t]+\{&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;With&lt;/span&gt;:&lt;br /&gt;
{&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;Regular Expression&lt;/span&gt;: on&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;Case sensitive&lt;/span&gt;: on&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;File name filter&lt;/span&gt;:&lt;br /&gt;
*Test.java, *TestCase.java&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// Look for import junit.framework;&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;Find&lt;/span&gt;:&lt;br /&gt;
import junit\.framework&lt;br /&gt;
Manually fix&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;Regular Expression&lt;/span&gt;: on&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;Case sensitive&lt;/span&gt;: on&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// Look for ignored tests (FIXME, disabled, ...)&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;Find&lt;/span&gt;:&lt;br /&gt;
public[ \t]+void[ \t]+\w+test&lt;br /&gt;
Manually fix&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;Regular Expression&lt;/span&gt;: on&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;Case sensitive&lt;/span&gt;: on&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// Look for dummy/empty tests&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;Find&lt;/span&gt;:&lt;br /&gt;
public[ \t]+void[ \t]+test[\w\d]*\(\s*\)\s*\{\s*(//[^\n]*)?\s*\}&lt;br /&gt;
Manually fix&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;Regular Expression&lt;/span&gt;: on&lt;br /&gt;
&lt;span style=&quot;color: #33ccff;&quot;&gt;Case sensitive&lt;/span&gt;: on&lt;/blockquote&gt;2) The project might not compile without an error after step 1, mostly because we still need to do the static import of various assertion methods (e.g. assertEquals, assertTrue, etc.)&lt;br /&gt;
&lt;br /&gt;
3) Since we use MockObjectTestCase from JMock with jUnit 3, we need to have a class level annotation of &quot;@&lt;span style=&quot;color: #ffcc33;&quot;&gt;RunWith(JMock.class)&lt;/span&gt;&quot;, remove the &quot;extends MockObjectTestCase&quot;, and manually define&lt;br /&gt;
&lt;blockquote&gt;&lt;br /&gt;
private final Mockery context = new Mockery();&lt;br /&gt;
...&lt;br /&gt;
xyz = context.mock(XYZ.class);&lt;br /&gt;
context.checking(new Expectations(){{}});&lt;/blockquote&gt;4) We then have to replace the test suite with junit 4 declaration styles:&lt;br /&gt;
&lt;blockquote&gt;&lt;br /&gt;
@RunWith(SomeDirectoryScanningSuite.class)&lt;br /&gt;
public class SomeTestSuite {&lt;br /&gt;
}&lt;/blockquote&gt;The &quot;SomeDirectoryScanningSuite&quot; has to extend &quot;org.junit.runners.Suite&quot;, for example&lt;br /&gt;
&lt;blockquote&gt;&lt;br /&gt;
public class SomeDirectoryScanningSuite extends Suite {&lt;br /&gt;
&lt;br /&gt;
public SomeDirectoryScanningSuite(Class testSuite) throws InitializationError, ClassNotFoundException {&lt;br /&gt;
super(testSuite, &lt;span style=&quot;color: #3366ff;&quot;&gt;new Class[]{SomeTest.class, AnotherTest.class}&lt;/span&gt;);&lt;br /&gt;
}&lt;br /&gt;
}&lt;/blockquote&gt;There are many different ways of specifying what test classes should be included in the above example.&lt;br /&gt;
&lt;br /&gt;
The example below is a test suite of a bunch of test suites/classes:&lt;br /&gt;
&lt;blockquote&gt;&lt;br /&gt;
@&lt;span style=&quot;color: #ffcc00;&quot;&gt;RunWith&lt;/span&gt;(Suite.class)&lt;br /&gt;
@&lt;span style=&quot;color: #ffcc00;&quot;&gt;Suite.SuiteClasses&lt;/span&gt;({&lt;br /&gt;
SomeTest.class, // junit 4 annotated test class&lt;br /&gt;
SomeTestSuite.class // junit 4 test suite&lt;br /&gt;
})&lt;br /&gt;
public class TestsSuite {}&lt;/blockquote&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yongouyang.blogspot.com/feeds/8942917952481900668/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://yongouyang.blogspot.com/2011/06/migrating-tests-from-junit-3-to-junit-4.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/8942917952481900668'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3705947190453566253/posts/default/8942917952481900668'/><link rel='alternate' type='text/html' href='http://yongouyang.blogspot.com/2011/06/migrating-tests-from-junit-3-to-junit-4.html' title='Migrating tests from junit 3 to junit 4'/><author><name>Yong Ouyang</name><uri>http://www.blogger.com/profile/05612250828808301428</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>