<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-5156332309817509524</id><updated>2012-01-28T02:45:29.581+11:00</updated><category term='story size'/><category term='RhinoUnit'/><category term='env.rhino.js'/><category term='sun developer day'/><category term='processing'/><category term='sd-card'/><category term='broken link'/><category term='SPFile'/><category term='android 2.1'/><category term='sqlplus'/><category term='conference'/><category term='tethering android smartphone mandriva linux'/><category term='software development'/><category term='category theory'/><category term='env.js'/><category term='psychology'/><category term='TDD'/><category term='connection string'/><category term='agile'/><category term='mandriva 2009'/><category term='unit test'/><category term='agile australia conference'/><category term='large data'/><category term='integrated testing'/><category term='rails'/><category term='graphing'/><category term='script'/><category term='servlet'/><category term='nosql'/><category term='cacti'/><category term='short-term reward'/><category term='user story'/><category term='remote server'/><category term='wget'/><category term='mp3 player'/><category term='remote database'/><category term='laptop'/><category term='database'/><category term='agile australia 2010'/><category term='linux'/><category term='visualization'/><category term='jQuery'/><category term='agileaus'/><category term='PFile'/><category term='java'/><category term='Javascript'/><category term='seminar'/><category term='sqlite'/><category term='integration test'/><category term='SYSDATE'/><category term='sansa e250'/><category term='SQL*Plus'/><category term='oracle'/><category term='rest'/><category term='video encoding'/><category term='eclair'/><category term='reference data'/><category term='unit testing'/><category term='snmp'/><category term='statistics'/><category term='Toshiba Portege M800'/><category term='yow'/><category term='fixed_date'/><title type='text'>Tech Talk</title><subtitle type='html'>All things geeking and high-tech that I happen to think of, encounter, buy or make.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://penguinman-techtalk.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5156332309817509524/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://penguinman-techtalk.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>penguinman</name><uri>http://www.blogger.com/profile/03293300286288413519</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp1.blogger.com/_2oGca8ZQVtc/R4WUQFuS1jI/AAAAAAAAAAM/YRVdoPal21U/S220/XRayPenguinAvatar.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>16</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-5156332309817509524.post-2396227406920378554</id><published>2011-12-05T06:34:00.035+11:00</published><updated>2011-12-06T20:44:19.504+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='conference'/><category scheme='http://www.blogger.com/atom/ns#' term='yow'/><title type='text'>My highlights of YOW! 2011 Melbourne</title><content type='html'>I attended the &lt;span style="font-weight:bold;"&gt;YOW! 2011&lt;/span&gt; Conference in Melbourne on 1-2 December 2011. &lt;br /&gt;&lt;br /&gt;&lt;h3&gt;The talks&lt;/h3&gt; &lt;br /&gt;There were many great talks, and some not-so-great. For me, two talks in particular stood out as special. If I only got to listen to these two and nothing else, it would've been worth it.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Product Engineering :- Mike Lee&lt;/h4&gt;&lt;br /&gt;I first saw Mike Lee's talk on &lt;a href="http://www.infoq.com/author/Mike-Lee"&gt;InfoQ&lt;/a&gt; several months ago and was really inspired by the passion of that guy, and was so happy to discover he was making an appearance at YOW.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-ckHp3mq9zks/TtvPdSRtGFI/AAAAAAAAAuM/qFAqrVPLNPs/s1600/IMAG0924.jpg" title="Mike Lee"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 241px;" src="http://4.bp.blogspot.com/-ckHp3mq9zks/TtvPdSRtGFI/AAAAAAAAAuM/qFAqrVPLNPs/s320/IMAG0924.jpg" border="0" alt="Mike Lee" id="BLOGGER_PHOTO_ID_5682363456887265362" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;He didn't impart any novel technical knowledge to us, nor did he tell us about the latest agile technique. In fact, everything he said in YOW was common-sense in hindsight, and virtually identical to the talks on InfoQ. And yet, it was pure pleasure to watch this man share his vision of what constituted a good product. I just did not get bored listening to this same talk for the 3rd time! Maybe it was his costume.&lt;br /&gt;&lt;br /&gt;Two things that stood out from the talk: &lt;ul&gt;&lt;li&gt;The hook :- the thing that makes a product special&lt;/li&gt;&lt;li&gt;Appsterdam :- New IT hub for freedom loving developers&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Temporally Quaquaversal Virtual Nanomachine Programming In Multiple Topologically Connected Quantum-Relativistic Parallel Timespaces...Made Easy! :- Damian Conway&lt;/h4&gt;&lt;br /&gt;Speaking of &lt;span style="font-style:italic;"&gt;the hook&lt;/span&gt;, the title of this talk did the job. Ever since I watched &lt;a href="http://www.youtube.com/watch?v=3Y-4GNIDQP4"&gt;Fred Simon's JavaPosse lightning talk on Positronic Variables&lt;/a&gt; a few months ago, I was curious about the Damian Conway's original work. As luck would have it, Damian came to tell us all about positronic variables.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-MT9sPp5f5ZY/TtvPvODQ6yI/AAAAAAAAAuY/1etDq6zGTok/s1600/IMAG0920.jpg" title="Damian Conway"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 241px;" src="http://2.bp.blogspot.com/-MT9sPp5f5ZY/TtvPvODQ6yI/AAAAAAAAAuY/1etDq6zGTok/s320/IMAG0920.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5682363764990602018" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Damian's Perl (and Rod logic) code was not very familiar to me, but his tongue-in-cheek introduction to quantum physics and the multi-verse was pure entertainment. Personally, I was not convinced that an &lt;span style="font-style:italic;"&gt;Einstein-Rosenberg bridge&lt;/span&gt; could be harnessed as described for running computer programs due to excessive energy requirements. A computer program using positronic variables would probably be unstable and generate incoherent results due to the unpredictable superposition of multiple variations of positronic values from an indeterminate number of future multi-verses.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Other notable talks&lt;/h4&gt;&lt;br /&gt;Jim Webber gave his usual talk on RESTful systems. I'd listened to his similarly themed talks before, but it was still entertaining to watch Jim Webber's performance. The one lesson that stuck in my mind was: Use an ATOM feed to publish events so that different clients could independently maintain / reconstruct their own internal states.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-yGOYXjER-5Q/TtvR-XP6vAI/AAAAAAAAAu8/QOKbJ0F4-dM/s1600/IMAG0915.jpg" title="Jim Webber"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 241px;" src="http://1.bp.blogspot.com/-yGOYXjER-5Q/TtvR-XP6vAI/AAAAAAAAAu8/QOKbJ0F4-dM/s320/IMAG0915.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5682366224180886530" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Another interesting talk was Dan Ingalls telling us about &lt;a href="http://lively-kernel.org/"&gt;Lively Kernel&lt;/a&gt;. Dan built a simple online load monitoring service simply using drag-on-drop from the Lively Kernel interface... cool.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;The games&lt;/h3&gt;&lt;br /&gt;As usual, there were lots of fun and games between talks. &lt;span style="font-style:italic;"&gt;Sensis&lt;/span&gt; developed a online (mobile) quiz game, &lt;span style="font-style:italic;"&gt;CodeJuicer&lt;/span&gt;, that morphed into to be a fun hacking game instead. Too bad I did not have a laptop with me to hack on it all day, though I did manage to hack it to zero-time from home at the end of Day 1. &lt;span style="font-style:italic;"&gt;Thoughtworks&lt;/span&gt; put up a quiz game and a movie title matching game, plus frozen nitrogen ice cream... all very popular. &lt;span style="font-style:italic;"&gt;Atlassian&lt;/span&gt; let us shoot Nerf guns... hard to beat that.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;The food&lt;/h3&gt;&lt;br /&gt;First day's food was not too good, but got better on the second day. The Beef Stroganoff was delicious. &lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-pd_JFYaKaVM/TtvQHzP3ttI/AAAAAAAAAuk/DJk_2d2Bd68/s1600/IMAG0921.jpg" title="Conference lunch Day 2"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 241px; height: 320px;" src="http://4.bp.blogspot.com/-pd_JFYaKaVM/TtvQHzP3ttI/AAAAAAAAAuk/DJk_2d2Bd68/s320/IMAG0921.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5682364187292448466" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The best parts were the free (real) coffee paid for by &lt;span style="font-style:italic;"&gt;Aconex&lt;/span&gt;, and the desserts, especially the mango mousse. &lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-HHfzs7UJIUQ/TtvRsn42wTI/AAAAAAAAAuw/8w4t42zMVcM/s1600/desserts.jpg"  title="Conference desserts"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 266px; height: 320px;" src="http://2.bp.blogspot.com/-HHfzs7UJIUQ/TtvRsn42wTI/AAAAAAAAAuw/8w4t42zMVcM/s320/desserts.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5682365919409914162" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Looking forward to YOW! 2012.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5156332309817509524-2396227406920378554?l=penguinman-techtalk.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://penguinman-techtalk.blogspot.com/feeds/2396227406920378554/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://penguinman-techtalk.blogspot.com/2011/12/my-highlights-of-yow-2011-melbourne.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5156332309817509524/posts/default/2396227406920378554'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5156332309817509524/posts/default/2396227406920378554'/><link rel='alternate' type='text/html' href='http://penguinman-techtalk.blogspot.com/2011/12/my-highlights-of-yow-2011-melbourne.html' title='My highlights of YOW! 2011 Melbourne'/><author><name>penguinman</name><uri>http://www.blogger.com/profile/03293300286288413519</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp1.blogger.com/_2oGca8ZQVtc/R4WUQFuS1jI/AAAAAAAAAAM/YRVdoPal21U/S220/XRayPenguinAvatar.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-ckHp3mq9zks/TtvPdSRtGFI/AAAAAAAAAuM/qFAqrVPLNPs/s72-c/IMAG0924.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5156332309817509524.post-8335264338025032893</id><published>2010-12-06T22:53:00.062+11:00</published><updated>2010-12-09T23:03:22.171+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='rest'/><category scheme='http://www.blogger.com/atom/ns#' term='conference'/><category scheme='http://www.blogger.com/atom/ns#' term='unit testing'/><category scheme='http://www.blogger.com/atom/ns#' term='visualization'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='nosql'/><category scheme='http://www.blogger.com/atom/ns#' term='category theory'/><category scheme='http://www.blogger.com/atom/ns#' term='yow'/><category scheme='http://www.blogger.com/atom/ns#' term='integrated testing'/><category scheme='http://www.blogger.com/atom/ns#' term='processing'/><title type='text'>Personal recollections of the YOW Melbourne Conference</title><content type='html'>I attended the &lt;span style="font-weight:bold;"&gt;YOW!2010&lt;/span&gt; Australia Software Developer Conference in Melbourne last week, and here is some recollection of my favourite talks. Please note this is all from memory, so I might some parts wrong.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Main themes&lt;/h3&gt;&lt;br /&gt;From the sessions I attended, some of the main recurring technical themes in this conference were:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-style:italic;"&gt;Consistency&lt;/span&gt; should be traded for &lt;span style="font-style:italic;"&gt;Availability&lt;/span&gt; in typical distributed systems&lt;/li&gt;&lt;li&gt;&lt;span style="font-style:italic;"&gt;Eventual consistency&lt;/span&gt; over &lt;span style="font-style:italic;"&gt;ACID&lt;/span&gt;&lt;/li&gt;&lt;li&gt;Always expect network failures, i.e. systems must be able to tolerate partitioning&lt;/li&gt;&lt;li&gt;NoSQL&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Most informative talks&lt;/h3&gt;&lt;br /&gt;&lt;h4&gt;The Rich Get Richer: Rails 3 :- Obie Fernadez&lt;/h4&gt;&lt;br /&gt;Obie gave a enlightening summary of the events leading to and the people involved in the merging of the &lt;span style="font-style:italic;"&gt;Merb&lt;/span&gt; and &lt;span style="font-style:italic;"&gt;Rails&lt;/span&gt; codebases, resulting in the newly released &lt;span style="font-style:italic;"&gt;Rails 3.0&lt;/span&gt;. The main drivers behind the new release were decoupling, modularity and prevention of code bloat. Many components of Rails 2 had been abstracted out and managed as third-party plug-in projects. He described &lt;span style="font-style:italic;"&gt;Rack&lt;/span&gt;, &lt;span style="font-style:italic;"&gt;Bundler&lt;/span&gt;, &lt;span style="font-style:italic;"&gt;Arel&lt;/span&gt; and the upgrade process from Rails 2.x to 3.0. I look forward to the day when I get the chance to put all these into practice.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Integrated Tests Are A Scam :- J. B. Rainsberger&lt;/h4&gt;&lt;br /&gt;Having written myriads of tests over the years, it was easy to lose sight of the different roles of tests in different parts of the system. JB gave an excellent refresher on two fundamentals of unit tests : &lt;span style="font-style:italic;"&gt;interaction testing&lt;/span&gt; and &lt;span style="font-style:italic;"&gt;contract testing&lt;/span&gt;. &lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_2oGca8ZQVtc/TP9yf0tdu3I/AAAAAAAAAi4/6Cy2AAt2nPk/s1600/InteractionTesting.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 283px; height: 320px;" src="http://2.bp.blogspot.com/_2oGca8ZQVtc/TP9yf0tdu3I/AAAAAAAAAi4/6Cy2AAt2nPk/s320/InteractionTesting.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5548279156994587506" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Interaction tests&lt;/span&gt; were the "normal" unit tests that I've been writing, where the external dependencies were replaced with stubs/mocks . In the example, he described interaction tests for a &lt;span style="font-style:italic;"&gt;client&lt;/span&gt; assessing an external &lt;span style="font-style:italic;"&gt;supplier&lt;/span&gt;. These tests were concerned with the pattern in which the &lt;span style="font-style:italic;"&gt;system-under-test (SUT)&lt;/span&gt; called out to the external system (mocked out), and how the SUT responded to various return values from the external system (stubbed).&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_2oGca8ZQVtc/TP4mO9MCtwI/AAAAAAAAAiQ/SkYb71JGcY0/s1600/ContractTesting.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 242px;" src="http://2.bp.blogspot.com/_2oGca8ZQVtc/TP4mO9MCtwI/AAAAAAAAAiQ/SkYb71JGcY0/s320/ContractTesting.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5547913829352126210" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Contract tests&lt;/span&gt; referred to tests that verified that an external system satisfied a certain API and expected behaviour, i.e. the contract. In a strongly-typed language like Java, this contract could be abstracted out from the actual implementation of the external system into a public interface, that our code could depend on. In fact, our code would only depend on this public interface, with no knowledge of the implementation. In a strongly-typed language, any implementation of this interface would then satisfy the minimum requirements of the contract, therefore, the real implementation could be replaced with a stub. As long as the stub passed the contract tests, it would in theory make no difference to our code. Hence, we could then write &lt;span style="font-style:italic;"&gt;integrated tests&lt;/span&gt; for our SUT that used the stub instead of the real implementation, which would make such tests extremely fast. &lt;br /&gt;&lt;br /&gt;Personally, I was not too convinced that interaction and contract tests could fully replace the need for integrated tests against real external systems. There would always be unexpected surprises lurking in system configuration, and some behaviour could not be adequately captured by the abstracted interface. Furthermore, in dynamically typed languages, it would be much harder to enforce that the stub fully implemented the public interface.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Designing and Implementing RESTful Application Protocols :- Ian Robinson&lt;/h4&gt;&lt;br /&gt;&lt;br /&gt;Ian walked us through an example from his new book, &lt;span style="font-style:italic;"&gt;REST in Practice&lt;/span&gt;, to illustrate the interactions of a client program ordering coffee beans from a coffee supplier via a RESTful interface.&lt;br /&gt;&lt;br /&gt;The client first asked the server for a list of allowed operations. After that, it requested a quote of available product prices. It then placed an order by resubmitting all the pricing data it had previously received back to the server. In this way, the client could maintain conversation state over a stateless protocol. A checksum of the data was used to prevent price tampering by the client. Finally, the server immediately returned a HTTP 202 response, before kicking off the long-running order fulfillment process asynchronously. &lt;br /&gt;&lt;br /&gt;Ian explained several basic concepts such as the use of media types, link relations and XForms in driving the process flow.&lt;br /&gt;&lt;br /&gt;I found Ian's talk to be clear and concise, therefore I'm putting his book on my wish-list.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Most interesting talks&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Exploring NoSQL :- Erik Meijer&lt;/h4&gt;&lt;br /&gt;This talk started a bit a slowly with an (mostly unecessary) explanation of how an object graph was represented in memory using pointers. This type of representation was embodied by &lt;span style="font-style:italic;"&gt;noSQL&lt;/span&gt;, whereas &lt;span style="font-style:italic;"&gt;SQL&lt;/span&gt; embodied a fully normalized relational view of data.&lt;br /&gt;&lt;br /&gt;Things became interesting when Erik started describing &lt;a href="http://en.wikipedia.org/wiki/Category_theory"&gt;Category Theory&lt;/a&gt;. Erik reasoned that because the direction of parent-child relationships was reversed between SQL and noSQL, they were duals of each other according to Category Theory. In other words, noSQL was actually "coSQL", i.e. for any statement that was true of SQL, the dual-statement (opposite meaning) would hold true for noSQL. Some examples of this duality were:&lt;br /&gt;&lt;table border="1"&gt;&lt;tr&gt;&lt;th align="center"&gt;SQL&lt;/th&gt;&lt;th align="center"&gt;noSQL&lt;/th&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;The identity is embodied in the row, i.e. primary key (extensional)&lt;/td&gt;&lt;td&gt;Identity of an object depended on other objects in the environment (intensional)&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Closed-world view of data&lt;/td&gt;&lt;td&gt;Open-world view of data&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Synchronous operations&lt;/td&gt;&lt;td&gt;Asynchronous operations&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;A very interesting concept indeed. Furthermore, this talk had the most obscure slide ever...&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_2oGca8ZQVtc/TQC5CLUeUII/AAAAAAAAAjI/HbkJCzgV8zY/s1600/IMAG0262-1.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 256px;" src="http://1.bp.blogspot.com/_2oGca8ZQVtc/TQC5CLUeUII/AAAAAAAAAjI/HbkJCzgV8zY/s320/IMAG0262-1.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5548638187969990786" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Computational Information Design :- Ben Fry&lt;/h4&gt;&lt;br /&gt;This talk was worth attending just for the visual candy itself. Ben talked about data visualization using his &lt;a href="http://www.processing.org/"&gt;Processing&lt;/a&gt; programming language (IMO really a DSL over Java 2D/3D). Some of the examples shown were really amazing, such as:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Mapping the program flow in old cartridge-based video games&lt;/li&gt;&lt;li&gt;Tracking changes to six editions of Charles Darwin's work&lt;/li&gt;&lt;li&gt;Comparing the human genome with other mammals&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_2oGca8ZQVtc/TPzV2tQEhJI/AAAAAAAAAh4/bPmI6kVfWOg/s1600/IMAG0265.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 241px;" src="http://1.bp.blogspot.com/_2oGca8ZQVtc/TPzV2tQEhJI/AAAAAAAAAh4/bPmI6kVfWOg/s320/IMAG0265.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5547543976850261138" /&gt;&lt;/a&gt;&lt;br /&gt;Ben then introduced &lt;a href="http://processingjs.org/"&gt;Processing.js&lt;/a&gt; that allowed code written in Processing to be run on any HTML5 compatible browser. People could simply go to &lt;a href="http://sketch.processing.org/"&gt;sketch.processing.org&lt;/a&gt; to write and run Processing code all within a Web browser. What was even more exciting was a port of the Processing runtime to &lt;span style="font-style:italic;"&gt;Android&lt;/span&gt;, which meant I could run Processing programs on my smartphone. Super cool!&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_2oGca8ZQVtc/TPzWR61kzAI/AAAAAAAAAiA/ggOeJ6kJZOg/s1600/IMAG0267-1.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 260px;" src="http://2.bp.blogspot.com/_2oGca8ZQVtc/TPzWR61kzAI/AAAAAAAAAiA/ggOeJ6kJZOg/s320/IMAG0267-1.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5547544444353694722" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Workshop&lt;/h3&gt;&lt;br /&gt;For me, the best part of the conference was the &lt;span style="font-style:italic;"&gt;iPhone&lt;/span&gt; workshop. Having done some &lt;span style="font-style:italic;"&gt;Android&lt;/span&gt; development, I was eager to see how things worked on the iPhone side. In this half-day workshop, I learned some basic syntax of &lt;span style="font-style:italic;"&gt;Objective-C&lt;/span&gt;, basic usage of &lt;span style="font-style:italic;"&gt;xcode&lt;/span&gt; IDE, some iPhone frameworks, and finally put together a simple iPhone application. My verdict of Objective-C :- dynamic typing and late binding were nice, but the extremely verbose syntax really sucked. I guess I'll stick with Android for now.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5156332309817509524-8335264338025032893?l=penguinman-techtalk.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://penguinman-techtalk.blogspot.com/feeds/8335264338025032893/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://penguinman-techtalk.blogspot.com/2010/12/personal-recollections-of-yow-melbourne.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5156332309817509524/posts/default/8335264338025032893'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5156332309817509524/posts/default/8335264338025032893'/><link rel='alternate' type='text/html' href='http://penguinman-techtalk.blogspot.com/2010/12/personal-recollections-of-yow-melbourne.html' title='Personal recollections of the YOW Melbourne Conference'/><author><name>penguinman</name><uri>http://www.blogger.com/profile/03293300286288413519</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp1.blogger.com/_2oGca8ZQVtc/R4WUQFuS1jI/AAAAAAAAAAM/YRVdoPal21U/S220/XRayPenguinAvatar.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_2oGca8ZQVtc/TP9yf0tdu3I/AAAAAAAAAi4/6Cy2AAt2nPk/s72-c/InteractionTesting.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5156332309817509524.post-9179569652907429539</id><published>2010-10-27T09:27:00.017+11:00</published><updated>2010-10-27T16:03:21.206+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tethering android smartphone mandriva linux'/><title type='text'>Tethering HTC Desire to Mandriva Linux 2010.1</title><content type='html'>The other day, I found myself in a situation where I needed to go online but there was no Wifi around. So I plugged my &lt;span style="font-style:italic;"&gt;HTC Desire (Android 2.1)&lt;/span&gt; smartphone into my laptop running &lt;span style="font-style:italic;"&gt;Mandriva Linux 2010.1 Spring&lt;/span&gt; and got &lt;a href="http://en.wikipedia.org/wiki/Tethering"&gt;tethering&lt;/a&gt; working. Here are the steps.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Preparation&lt;/h3&gt;&lt;br /&gt;While connected to a wired or Wifi Internet, install the &lt;span style="font-style:italic;"&gt;dhcpcd&lt;/span&gt; package. As root user (or using sudo):&lt;br /&gt;&lt;code&gt;$ urpmi dhcpcd&lt;/code&gt;&lt;br /&gt; &lt;br /&gt;It was also useful to install &lt;span style="font-style:italic;"&gt;usbview&lt;/span&gt;.&lt;br /&gt;&lt;code&gt;$ urpmi usbview&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Connecting the phone&lt;/h3&gt;&lt;br /&gt;First, connect to &lt;span style="font-style:italic;"&gt;Mobile Internet&lt;/span&gt; from the phone (this &lt;span style="font-weight:bold;"&gt;must&lt;/span&gt; be done before plugging into laptop). Then plug the phone into the laptop using the USB cable and select the &lt;span style="font-style:italic;"&gt;Internet sharing&lt;/span&gt; mode.&lt;br /&gt;&lt;br /&gt;On the laptop, start &lt;span style="font-style:italic;"&gt;usbview&lt;/span&gt; and confirm that &lt;span style="font-style:italic;"&gt;Android Phone&lt;/span&gt; was shown. &lt;br /&gt;&lt;br /&gt;As root user, start the usb0 interface:&lt;br /&gt;&lt;code&gt;$ ifconfig usb0 up&lt;/code&gt;&lt;br /&gt;Check that it had really started the usb0 interface:&lt;br /&gt;&lt;code&gt;$ ifconfig usb0&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Getting an address&lt;/h3&gt;&lt;br /&gt;Finally, on the laptop, obtain an address from the phone using:&lt;br /&gt;&lt;code&gt;$ dhcpcd usb0&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;When this command had completed, confirm that an IP address had been assigned using:&lt;br /&gt;&lt;code&gt;$ ifconfig usb0&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;After this, the laptop can get online using the HTC Desire phone as a gateway.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5156332309817509524-9179569652907429539?l=penguinman-techtalk.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://penguinman-techtalk.blogspot.com/feeds/9179569652907429539/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://penguinman-techtalk.blogspot.com/2010/10/tethering-htc-desire-to-mandriva-linux.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5156332309817509524/posts/default/9179569652907429539'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5156332309817509524/posts/default/9179569652907429539'/><link rel='alternate' type='text/html' href='http://penguinman-techtalk.blogspot.com/2010/10/tethering-htc-desire-to-mandriva-linux.html' title='Tethering HTC Desire to Mandriva Linux 2010.1'/><author><name>penguinman</name><uri>http://www.blogger.com/profile/03293300286288413519</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp1.blogger.com/_2oGca8ZQVtc/R4WUQFuS1jI/AAAAAAAAAAM/YRVdoPal21U/S220/XRayPenguinAvatar.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5156332309817509524.post-2437772559903763698</id><published>2010-09-15T22:28:00.076+10:00</published><updated>2010-09-18T00:29:55.077+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile australia 2010'/><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='agile australia conference'/><category scheme='http://www.blogger.com/atom/ns#' term='agileaus'/><title type='text'>Agile Australia 2010: Personal Recollections</title><content type='html'>I attended the &lt;span style="font-weight:bold;"&gt;Agile Australia 2010&lt;/span&gt; Conference in Crown Conference Centre, Melbourne, on September 15 and 16, 2010. Here are some of my personal recollections, remarks and photos.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;DAY 1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;First impression when I got to the venue :- lots of people. The expected Agile consulting/training firms were there with their promotional booths (some free iPads to give away), with &lt;span style="font-style:italic;"&gt;Thoughtworks&lt;/span&gt; being prominently at the centre. Personally, I was more interested in training courses, and so grabbed some brochures from &lt;span style="font-style:italic;"&gt;Renewtek&lt;/span&gt; and &lt;span style="font-style:italic;"&gt;Agile Academy&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_2oGca8ZQVtc/TJDATbNApNI/AAAAAAAAAc0/1M8cwkTa2eE/s1600/IMAG0166.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 241px;" src="http://4.bp.blogspot.com/_2oGca8ZQVtc/TJDATbNApNI/AAAAAAAAAc0/1M8cwkTa2eE/s320/IMAG0166.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5517120983481230546" /&gt;&lt;/a&gt;&lt;span style="font-size: 75%;"&gt;Promotional booths and the crowd&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The conference was kicked off with a keynote talk by &lt;span style="font-weight:bold;"&gt;Jim Highsmith&lt;/span&gt;, who presented various pieces of data, statistics and graphs to tell everyone how to measure Agile successes. &lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_2oGca8ZQVtc/TJDB4tEq3TI/AAAAAAAAAc8/BVRU03zqGjs/s1600/IMAG0165.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 241px;" src="http://3.bp.blogspot.com/_2oGca8ZQVtc/TJDB4tEq3TI/AAAAAAAAAc8/BVRU03zqGjs/s320/IMAG0165.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5517122723444874546" /&gt;&lt;/a&gt;&lt;span style="font-size: 75%;"&gt;Jim Highsmith's keynote talk&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;This was immediately followed by an excellent talk by &lt;span style="font-weight:bold;"&gt;Jeff Smith&lt;/span&gt; of Suncorp. His point that trust and respect were the crucial values necessary to foster effective teams resonated with my own recent experience with several teams in my own company. He also introduced the &lt;span style="font-style:italic;"&gt;Agile Academy&lt;/span&gt;, which I didn't know of before.&lt;br /&gt;&lt;br /&gt;Next, the conference was split up into three parallel streams. I attended the talks by &lt;span style="font-weight:bold;"&gt;Ben Hogan&lt;/span&gt; (&lt;span style="font-style:italic;"&gt;Using Agile techniques to adopt Agile&lt;/span&gt;) and &lt;span style="font-weight:bold;"&gt;Neal Ford&lt;/span&gt; (&lt;span style="font-style:italic;"&gt;Implementing Emergent Design&lt;/span&gt;). &lt;br /&gt;&lt;br /&gt;Ben introduced us to John Kotter's 8 steps to successfully implement change, that he contended were not adaptive due to lack of any feedback mechanism. Therefore, he proposed using Scrum's feedback cycle to introduce adaptability to some of these steps. In order to introduced changes such as Agile adoption to people and organizations, he suggested using a longer iteration/cycle time (1 month) than in software development.&lt;br /&gt;&lt;br /&gt;I was initially more interested in Neal's topic due to its developer-centric focus. He spent quite a lot of time explaining software design concepts such as:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;inherent and accidental complexity&lt;/li&gt;&lt;li&gt;technical debt and negotiating payment&lt;/li&gt;&lt;li&gt;over-engineering for genericness&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;He presented enablers of emergent designs such as:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;test-driven design&lt;/li&gt;&lt;li&gt;refactoring to harvest idiomatic patterns&lt;/li&gt;&lt;/ul&gt; He even went through some calculations of code complexity and class coupling metrics. However, given that Neal's talk was marked as &lt;span style="font-style:italic;"&gt;for those thoroughly experienced with Agile&lt;/span&gt;, I was actually a bit disappointed to find it rather lacking in novel in-depth content. Surely, experienced agile practitioners would already know about complexity and technical debt. I doubt any experienced developer would have learned much from the refactoring examples. I did learn something useful though:- In Pacman, a ghost could not detect Pacman running right up next to it (his example of anti-object).&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_2oGca8ZQVtc/TJDB4zpvQ5I/AAAAAAAAAdE/r5MUcNWmeyE/s1600/IMAG0168.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 241px; height: 320px;" src="http://1.bp.blogspot.com/_2oGca8ZQVtc/TJDB4zpvQ5I/AAAAAAAAAdE/r5MUcNWmeyE/s320/IMAG0168.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5517122725210964882" /&gt;&lt;/a&gt;&lt;span style="font-size: 75%;"&gt;Neal Ford on idiomatic patterns and software design&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;By lunch time, I was eager to find out what delicacies might be served in the buffet. Alas, it was just beef rolls and sandwiches. Nothing to brag about. How I missed the comparatively luxurious offerings from the bygone &lt;a href="http://penguinman-techtalk.blogspot.com/2008/11/sun-developer-day-2008-melbourne.html"&gt;Sun Developer Days&lt;/a&gt; conferences.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_2oGca8ZQVtc/TJDB6Mo0N9I/AAAAAAAAAdc/741FpK5_-rg/s1600/IMAG0169.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 241px; height: 320px;" src="http://3.bp.blogspot.com/_2oGca8ZQVtc/TJDB6Mo0N9I/AAAAAAAAAdc/741FpK5_-rg/s320/IMAG0169.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5517122749097850834" /&gt;&lt;/a&gt;&lt;span style="font-size: 75%;"&gt;Sandwiches, rolls and some salad for lunch&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;After lunch, I watched the panel session, where five top agile practitioners sat together to discuss their preferred flavours of Agile. It was nice to be able to ask questions using Twitter. I was particularly interested in Kanban, and managed to tweet a Kanban-related question for &lt;span style="font-weight:bold;"&gt;Bruce Taylor&lt;/span&gt; from the comfort of my phone. By the way, my boss was also one of the panel members.&lt;br /&gt;&lt;br /&gt;This was followed by the lightning talks, my favourite of which was &lt;span style="font-weight:bold;"&gt;Ben Arnott&lt;/span&gt;'s &lt;span style="font-style:italic;"&gt;Agile@Home&lt;/span&gt;. A light-hearted, entertaining contrast to the other serious topics of the day.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_2oGca8ZQVtc/TJDB5UGTrAI/AAAAAAAAAdM/vlDYt1c46aQ/s1600/IMAG0170.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 241px;" src="http://3.bp.blogspot.com/_2oGca8ZQVtc/TJDB5UGTrAI/AAAAAAAAAdM/vlDYt1c46aQ/s320/IMAG0170.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5517122733920726018" /&gt;&lt;/a&gt;&lt;span style="font-size: 75%;"&gt;One of the lightning talks&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The last full talk I attended on Day 1 was &lt;span style="font-weight:bold;"&gt;Craig Smith&lt;/span&gt;'s &lt;span style="font-style:italic;"&gt;Building An A-Team&lt;/span&gt;. The content itself was nothing new, mainly around how to identify and lead good teams. However it was concisely and brilliantly delivered with good humor.&lt;br /&gt;&lt;br /&gt;Finally I decided to pop into the Agile Games session next door midway. This was what I saw :&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_2oGca8ZQVtc/TJDB5rupNxI/AAAAAAAAAdU/cFjfLEhj0ZY/s1600/IMAG0172.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 241px;" src="http://2.bp.blogspot.com/_2oGca8ZQVtc/TJDB5rupNxI/AAAAAAAAAdU/cFjfLEhj0ZY/s320/IMAG0172.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5517122740263925522" /&gt;&lt;/a&gt;&lt;span style="font-size: 75%;"&gt;Not too sure what was going on here&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Groups of people throwing balls around. After 30 minutes and still failing to make sense of this, I switched to another room and caught the end of &lt;span style="font-weight:bold;"&gt;Jay Jenkins&lt;/span&gt;' talk on how ANZ did Agile. &lt;br /&gt;&lt;br /&gt;Thus ended Day 1.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;DAY 2&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The second day started with an awesome talk by &lt;span style="font-weight:bold;"&gt;Martin Fowler&lt;/span&gt;. He reminded us of the reasons why we did Agile, the advantages of adapting to late changes, the importance of continuous integration and delivery, and finally the different types of technical debt. Of course, the best part was his impersonation of Uncle Bob Martin.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_2oGca8ZQVtc/TJIOuZdTmNI/AAAAAAAAAec/jORvEPk43Ag/s1600/IMAG0173.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand; width: 320px; height: 241px;" src="http://1.bp.blogspot.com/_2oGca8ZQVtc/TJIOuZdTmNI/AAAAAAAAAec/jORvEPk43Ag/s320/IMAG0173.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5517488683752855762" /&gt;&lt;/a&gt;&lt;span style="font-size: 75%;"&gt;Martin Fowler giving the first talk of Day 2&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Next, I attended a couple of more practical talks. First was &lt;span style="font-weight:bold;"&gt;Jason Yip&lt;/span&gt; and &lt;span style="font-weight:bold;"&gt;Marina Chiovetti&lt;/span&gt; on how to properly measure and assess Agile adoption and success in different organizations. They pointed out that external assessments were misleading because results could be faked. Only when an organization defined a vision ("true north"), be transparent and internally reflected on how it was progressing towards this vision could it have a true understanding of its level of Agile adoption.&lt;br /&gt;&lt;br /&gt;The second talk was very relevant to me as a developer. &lt;span style="font-weight:bold;"&gt;Chris Mountford&lt;/span&gt; described how he solved monster builds problems in &lt;span style="font-style:italic;"&gt;Atlassian&lt;/span&gt;. His approach involved the following:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Always measure first&lt;/li&gt;&lt;li&gt;Be selective about what to test&lt;/li&gt;&lt;li&gt;Parallelize tests&lt;/li&gt;&lt;li&gt;Canary tests with a good proven version to detect environment/external problems&lt;/li&gt;&lt;li&gt;Choosing the right tools&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;At this point, the &lt;span style="font-style:italic;"&gt;#agileaus&lt;/span&gt; Twitter feed was flooded with reports of how fantastic talks in the other rooms were. All of the talks during this time slot looked interesting, but alas I could only be in one place at a time. &lt;br /&gt;&lt;br /&gt;I felt lunch on Day 2 was a slight improvement over the day before. The salad, rolls and sandwiches were still there, but they tasted a bit better, or maybe I'd lowered my expectations.   &lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_2oGca8ZQVtc/TJINqTTRjjI/AAAAAAAAAeU/6ivXef2KihU/s1600/IMAG0176.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 241px; height: 320px;" src="http://3.bp.blogspot.com/_2oGca8ZQVtc/TJINqTTRjjI/AAAAAAAAAeU/6ivXef2KihU/s320/IMAG0176.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5517487513869061682" /&gt;&lt;/a&gt;&lt;span style="font-size: 75%;"&gt;More salad, rolls and sandwiches for lunch&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;In my opinion, the talk with the best analogy (Death Star) and slides would be &lt;span style="font-weight:bold;"&gt;Nigel Dalton&lt;/span&gt;'s talk after lunch. Nigel described how various non-IT teams (lawyers, finance, publishers etc) in &lt;span style="font-style:italic;"&gt;Lonely Planet&lt;/span&gt; adopted Agile. Photos of their various &lt;span style="font-style:italic;"&gt;Kanban&lt;/span&gt; boards managed to convey how these teams track their work in a highly effective and visible way. It was reassuring to know that Agile was not just restricted to us IT folks. Having personally spent a few months working at the &lt;span style="font-style:italic;"&gt;Lonely Planet&lt;/span&gt; office in Footscray a few years ago, I was happy to see such a drastic transformation throughout the company.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_2oGca8ZQVtc/TJINp3yxsGI/AAAAAAAAAeM/qh4W4ncKDYA/s1600/IMAG0177.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 241px;" src="http://1.bp.blogspot.com/_2oGca8ZQVtc/TJINp3yxsGI/AAAAAAAAAeM/qh4W4ncKDYA/s320/IMAG0177.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5517487506484998242" /&gt;&lt;/a&gt;&lt;span style="font-size: 75%;"&gt;Nigel Dalton described the Death Star as the perfect Agile project : "Build the weapon first!"&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Nigel's entertaining presentation was followed by a more serious, enterprise-level talk by &lt;span style="font-weight:bold;"&gt;John Sullivan&lt;/span&gt; from &lt;span style="font-style:italic;"&gt;Sensis&lt;/span&gt;, on how best to do "&lt;span style="font-style:italic;"&gt;Enterprise Architecture&lt;/span&gt;" in an Agile company. This was a topic that interested me as a developer. Some of John's main points were:  &lt;br /&gt;&lt;ul&gt;&lt;li&gt;Traditional enterprise architectural groups were unnecessary barriers between developers and business&lt;/li&gt;&lt;li&gt;Architects produced elegant but unworkable solutions&lt;/li&gt;&lt;li&gt;Better to form a temporary group of senior developers to sit with business in a requirements gathering session to identify key business and technical requirements&lt;/li&gt;&lt;li&gt;Implement an initial version of the architecture in code, or sometimes spikes, to gain technical insights to be able to provide estimates&lt;/li&gt;&lt;li&gt;"Architect" as a temporary role on an as-needed basis, not a job title&lt;/li&gt;&lt;li&gt;Get rid of people who get in the way&lt;/li&gt;&lt;li&gt;Split the backlog into &lt;ul&gt;&lt;li&gt;in-build : Only build this, but make the system extensible&lt;/li&gt;&lt;li&gt;in-plan : Something to keep in mind, but expect this to change&lt;/li&gt;&lt;li&gt;future-release : (I would guess don't worry about this)&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_2oGca8ZQVtc/TJINpYyNzVI/AAAAAAAAAeE/1LAOjZ_YQmM/s1600/IMAG0179.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 241px;" src="http://3.bp.blogspot.com/_2oGca8ZQVtc/TJINpYyNzVI/AAAAAAAAAeE/1LAOjZ_YQmM/s320/IMAG0179.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5517487498161147218" /&gt;&lt;/a&gt;&lt;span style="font-size: 75%;"&gt;John Sullivan declaring the end of the Enterprise Architect job title&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Up to this point, DevOps people might have felt a bit left-out. Luckily, &lt;span style="font-weight:bold;"&gt;Jez Humble&lt;/span&gt; changed that with his informative presentation on &lt;span style="font-style:italic;"&gt;DevOps and Agile Release Management&lt;/span&gt;. This was another area I had a special interest in. Jez stressed the importance of the definition of DONE, i.e. DONE when a feature got to production. The problems he presented were that DevOps people: &lt;ul&gt;&lt;li&gt;used to see changes as too risky&lt;/li&gt;&lt;li&gt;resisted new changes because they favoured stability&lt;/li&gt;&lt;li&gt;spent too much time firefighting rather than doing strategic work&lt;/li&gt;&lt;/ul&gt;. The solutions he presented were:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Culture : Have cross-functional delivery teams. Adopt Kanban to schedule work.&lt;/li&gt;&lt;li&gt;Automation : Environments could be procured using cloud computing and configuration managed by Puppet or Chef. He even mentioned cucumber-nagios which interested me a lot.&lt;/li&gt;&lt;li&gt;Measurement : Collate business and technical metrics. Perform root cause analysis.&lt;/li&gt;&lt;li&gt;Sharing : With big visible displays&lt;/li&gt;&lt;li&gt;Overcoming objections : By showing visibility, control, automated scripts and auditing&lt;/li&gt;&lt;li&gt;Deployment pipeline : Automatic deployment to various environments including production.&lt;/li&gt;&lt;/ul&gt; That was a lot of new tools for me to read up on.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_2oGca8ZQVtc/TJINo-Gi63I/AAAAAAAAAd8/pSzh4LSjCyY/s1600/IMAG0180.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 241px; height: 320px;" src="http://2.bp.blogspot.com/_2oGca8ZQVtc/TJINo-Gi63I/AAAAAAAAAd8/pSzh4LSjCyY/s320/IMAG0180.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5517487490998659954" /&gt;&lt;/a&gt;&lt;span style="font-size: 75%;"&gt;Jez Humble talking about DevOps&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Finally, I attended the Open Space session, first with the lightning talks group, then  finally with a group discussing automated performance tests. The idea sounded good, but I felt there wasn't enough time to flesh out too much technical details.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_2oGca8ZQVtc/TJINn71yTAI/AAAAAAAAAd0/I3W8iV1iaIk/s1600/IMAG0181.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 241px;" src="http://2.bp.blogspot.com/_2oGca8ZQVtc/TJINn71yTAI/AAAAAAAAAd0/I3W8iV1iaIk/s320/IMAG0181.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5517487473211624450" /&gt;&lt;/a&gt;&lt;span style="font-size: 75%;"&gt;One of the Open Space lightning talks&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;At 4:30 pm, snacks and drinks came out for the final networking session that concluded the conference.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;CONCLUSION&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Overall a worthwhile conference to gain an overview of the current state of Agile. I was glad to see the previously neglected area of DevOps getting some attention. As for the technically focussed talks, I would have preferred: &lt;ul&gt;&lt;li&gt;more technical depth&lt;/li&gt;&lt;li&gt;updates on the latest development, testing or monitoring tools&lt;/li&gt;&lt;li&gt; some discussion on the latest Agile practices when developing on mobile devices&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Maybe next year...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5156332309817509524-2437772559903763698?l=penguinman-techtalk.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://penguinman-techtalk.blogspot.com/feeds/2437772559903763698/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://penguinman-techtalk.blogspot.com/2010/09/agile-australia-2010-personal.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5156332309817509524/posts/default/2437772559903763698'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5156332309817509524/posts/default/2437772559903763698'/><link rel='alternate' type='text/html' href='http://penguinman-techtalk.blogspot.com/2010/09/agile-australia-2010-personal.html' title='Agile Australia 2010: Personal Recollections'/><author><name>penguinman</name><uri>http://www.blogger.com/profile/03293300286288413519</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp1.blogger.com/_2oGca8ZQVtc/R4WUQFuS1jI/AAAAAAAAAAM/YRVdoPal21U/S220/XRayPenguinAvatar.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_2oGca8ZQVtc/TJDATbNApNI/AAAAAAAAAc0/1M8cwkTa2eE/s72-c/IMAG0166.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5156332309817509524.post-8191093704178097576</id><published>2010-08-06T16:38:00.005+10:00</published><updated>2010-08-06T17:02:33.207+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='wget'/><category scheme='http://www.blogger.com/atom/ns#' term='broken link'/><category scheme='http://www.blogger.com/atom/ns#' term='script'/><title type='text'>Detect broken links on a Web site using wget</title><content type='html'>The other day, I started thinking about writing a simple Web site validator that detects broken links on a Web site, similar to &lt;a href="http://validator.w3.org/checklink"&gt;W3C Link Checker&lt;/a&gt;. After looking at various code samples in Java, Ruby, etc, I figured out that &lt;span style="font-weight:bold;"&gt;GNU wget 1.12&lt;/span&gt; on my Linux machine could do the job just fine, with no programming required. It even detected broken resource links in CSS, not just broken &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; links. &lt;br /&gt;&lt;br /&gt;Here is how to write a simple script to check the site. First, pretend to be a Mozilla-based browser and spider the site to the depth of one level:&lt;pre&gt;&lt;br /&gt;wget --spider -r -l 1 --header='User-Agent: Mozilla/5.0' \&lt;br /&gt;-o wget_errors.txt http://the_site_i_want_to_validate&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Then, simply look at the return code to determine if there is any error. If the code is larger than zero, there is an error.&lt;pre&gt;&lt;br /&gt;EXIT_CODE=$?&lt;br /&gt;if [ $EXIT_CODE -gt 0 ]; then&lt;br /&gt;    echo "ERROR: Found broken link(s)"&lt;br /&gt;    exit 1&lt;br /&gt;fi&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;To find out the actual links in question, just grep for &lt;span style="font-weight:bold;"&gt;404&lt;/span&gt; in the wget error log.&lt;pre&gt;&lt;br /&gt;BROKEN_LINKS=`grep -B 2 '404' wget_errors.txt`&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The &lt;code&gt;-B 2&lt;/code&gt; outputs the 2 lines above any matching line, which in this case contains the broken link in question.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5156332309817509524-8191093704178097576?l=penguinman-techtalk.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://penguinman-techtalk.blogspot.com/feeds/8191093704178097576/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://penguinman-techtalk.blogspot.com/2010/08/detect-broken-links-on-web-site-using.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5156332309817509524/posts/default/8191093704178097576'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5156332309817509524/posts/default/8191093704178097576'/><link rel='alternate' type='text/html' href='http://penguinman-techtalk.blogspot.com/2010/08/detect-broken-links-on-web-site-using.html' title='Detect broken links on a Web site using wget'/><author><name>penguinman</name><uri>http://www.blogger.com/profile/03293300286288413519</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp1.blogger.com/_2oGca8ZQVtc/R4WUQFuS1jI/AAAAAAAAAAM/YRVdoPal21U/S220/XRayPenguinAvatar.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5156332309817509524.post-1625780591777546411</id><published>2010-08-03T16:13:00.066+10:00</published><updated>2010-10-07T17:23:27.718+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sqlite'/><category scheme='http://www.blogger.com/atom/ns#' term='reference data'/><category scheme='http://www.blogger.com/atom/ns#' term='eclair'/><category scheme='http://www.blogger.com/atom/ns#' term='large data'/><category scheme='http://www.blogger.com/atom/ns#' term='database'/><category scheme='http://www.blogger.com/atom/ns#' term='android 2.1'/><category scheme='http://www.blogger.com/atom/ns#' term='sd-card'/><title type='text'>Loading large reference database in Android</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_2oGca8ZQVtc/TFkShGt5j_I/AAAAAAAAAZ4/SAZ5iATQYNg/s1600/android-db.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 320px; height: 223px;" src="http://1.bp.blogspot.com/_2oGca8ZQVtc/TFkShGt5j_I/AAAAAAAAAZ4/SAZ5iATQYNg/s320/android-db.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5501448779757883378" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Reference data&lt;/span&gt; normally refers to (mostly) read-only data that is used to validate or resolve other pieces of data. For example, a list of postcodes and suburbs, that can be used to provide auto-suggestions in a UI or validate a user's address. &lt;br /&gt;&lt;br /&gt;I recently developed an &lt;span style="font-style:italic;"&gt;Android (version 2.1 / Eclair)&lt;/span&gt; application that used a large set of reference data, stored in a &lt;span style="font-style:italic;"&gt;SQLite&lt;/span&gt; database. The fact that this was targeted for Android smartphones introduced some constraints in the loading of this data that would not be present for a desktop or Web application, primarily &lt;span style="font-style:italic;"&gt;processing time&lt;/span&gt; and &lt;span style="font-style:italic;"&gt;storage space&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;The initial design was based on my prior experience working on Web applications. It involved packaging a largish (~10MB) text file into the &lt;span style="font-style:italic;"&gt;apk&lt;/span&gt; archive. The application performed a one-time initialization step that loaded this file, parsed it and executed SQL statements to insert rows into the database. The application then accessed the reference data via a subclass of &lt;a href="http://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html"&gt;&lt;code&gt;SQLiteOpenHelper&lt;/code&gt;&lt;/a&gt;. It soon became apparent that this would not work in the Android world, due to the following reasons. &lt;ul&gt;&lt;li&gt;Loading the database, even if its a once-off, took too long. People are not likely to want to wait for many more minutes, especially after waiting for the 10MB download.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;The database storage took up 10+MB, and when combined with the input text file, totalled 20+MB. Android 2.1 required the application to be installed onto the phone's limited internal memory, where 20MB was a relatively massive chunk.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;The input text file in the apk archive could not be removed after initialization, so it just uselessly consumed precious phone memory.&lt;/li&gt;&lt;/ul&gt; After a few tries, I arrived at the following final design that seemed to solve these problems.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Preload database&lt;/h3&gt; The database loading code had to be removed from the Android code and rewritten as a separate program. This program read the text input file and inserted the rows into a SQLite database, with the database file stored on my desktop. Note that the primary key column of the reference table should be named &lt;code&gt;_id&lt;/code&gt; and the following must be added to the database for it to be usable by Android: &lt;br /&gt;&lt;code&gt;&lt;br /&gt;CREATE TABLE android_metadata (locale TEXT);&lt;br /&gt;INSERT INTO android_metadata VALUES('en_US');&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;This preloaded database file was then uploaded to a Web site so that it could be downloaded by the Android application.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Download database&lt;/h3&gt; The Android application didn't need to be packaged with the text input file any more, hence trimming the &lt;span style="font-style:italic;"&gt;apk&lt;/span&gt; archive from 10+MB to a few hundred KB. The application's starting &lt;code&gt;Activity&lt;/code&gt; would check and download the database file if it didn't already exist on the SD-Card. According to the &lt;a href="http://developer.android.com/guide/topics/data/data-storage.html"&gt;Android Dev Guide on Data Storage&lt;/a&gt;, the proper place to save the database file would be: &lt;ul&gt;&lt;br /&gt;&lt;li&gt;for Android 2.2 and above :- the directory returned by &lt;a href="http://developer.android.com/reference/android/content/Context.html#getExternalFilesDir(java.lang.String)"&gt;&lt;code&gt;getExternalFilesDir()&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;for Android 2.1 :- the directory starting with &lt;a href="http://developer.android.com/reference/android/os/Environment.html#getExternalStorageDirectory()"&gt;&lt;code&gt;getExternalStorageDirectory()&lt;/code&gt;&lt;/a&gt;, then appended with &lt;code&gt;/Android/data/&amp;lt;package_name&amp;gt;/&amp;lt;file_type&amp;gt;&lt;/code&gt;, which resolved to something like &lt;code&gt;/sdcard/Android/data/com.mycompany.myapp/db&lt;/code&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt; I had to use the latter option as I was targeting 2.1. &lt;br /&gt;&lt;br /&gt;It was important to ensure that the UI was not frozen during the few minutes it took to download the 10+MB database file. That meant that the downloading code must be executed in a separate thread to the main UI thread. The best way to achieve this was to create a subclass of &lt;a href="http://developer.android.com/reference/android/os/AsyncTask.html"&gt;&lt;code&gt;AsyncTask&lt;/code&gt;&lt;/a&gt; and put the downloading code in its &lt;code&gt;doInBackground()&lt;/code&gt; method. This class also displayed a &lt;a href="http://developer.android.com/reference/android/app/ProgressDialog.html"&gt;&lt;code&gt;ProgressDialog&lt;/code&gt;&lt;/a&gt; to keep the user informed, and acquired a &lt;a href="http://developer.android.com/reference/android/os/PowerManager.WakeLock.html"&gt;&lt;code&gt;WakeLock&lt;/code&gt;&lt;/a&gt; (&lt;code&gt;SCREEN_DIM_WAKE_LOCK&lt;/code&gt;) to prevent the phone from going to sleep. Another important thing to remember was to prevent the screen orientation from changing when the phone was flipped over while the &lt;a href="http://developer.android.com/reference/android/app/ProgressDialog.html"&gt;&lt;code&gt;ProgressDialog&lt;/code&gt;&lt;/a&gt; was showing, otherwise the application would crash when the dialog was dismissed. This was achieved by temporarily setting the &lt;code&gt;requestedOrientation&lt;/code&gt; property of the activity to "no-sensor". Here is the skeleton code of the AsyncTask:&lt;pre&gt;&lt;br /&gt;// FileDownloader is my own delegate class that performs the &lt;br /&gt;// actual downloading and is initialized with the source URL.&lt;br /&gt;public class InitializeDatabaseTask extends&lt;br /&gt;        AsyncTask&amp;lt;FileDownloader, Integer, Object&amp;gt; {&lt;br /&gt;    private ProgressDialog progressDialog;&lt;br /&gt;    private File dbFile;&lt;br /&gt;    private PowerManager.WakeLock wakeLock;&lt;br /&gt;    private Activity activity;&lt;br /&gt;    private transient int originalRequestedOrientation;&lt;br /&gt;&lt;br /&gt;    public InitializeDatabaseTask(Activity activity, File dbFile) {&lt;br /&gt;        super();&lt;br /&gt;        this.dbFile = dbFile;&lt;br /&gt;        this.activity = activity;&lt;br /&gt;&lt;br /&gt;        wakeLock = ...;  // Obtain a wakelock for SCREEN_DIM_WAKE_LOCK             &lt;br /&gt;        progressDialog = ...;  // Create a ProgressDialog instance with title, message ,etc&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    protected void onPreExecute() {&lt;br /&gt;        super.onPreExecute();&lt;br /&gt;        originalRequestedOrientation = activity.getRequestedOrientation();&lt;br /&gt;        activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);&lt;br /&gt;        wakeLock.acquire();&lt;br /&gt;        progressDialog.show();&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @Override&lt;br /&gt;    protected Object doInBackground(FileDownloader... params) {&lt;br /&gt;        FileDownloader downloader = params[0];&lt;br /&gt;        try {&lt;br /&gt;            downloader.downloadTo(dbFile);&lt;br /&gt;        } catch (IOException e) {&lt;br /&gt;            throw new AndroidRuntimeException(e);&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        return null;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @Override&lt;br /&gt;    protected void onPostExecute(Object result) {&lt;br /&gt;        super.onPostExecute(result);&lt;br /&gt;        progressDialog.dismiss();&lt;br /&gt;        wakeLock.release();&lt;br /&gt;        activity.setRequestedOrientation(originalRequestedOrientation);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The main &lt;code&gt;Activity&lt;/code&gt; used &lt;code&gt;InitializeDatabaseTask&lt;/code&gt; like so:&lt;pre&gt;&lt;br /&gt;File dbFile = ...; // File pointing to /sdcard/Android/data/com.mycompany.myapp/db&lt;br /&gt;new InitializeDatabaseTask(this, dbFile).execute(new FileDownloader(DOWNLOAD_DB_URL));&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Mount SD-Card in emulator&lt;/h3&gt; I developed the application mainly using the &lt;span style="font-style:italic;"&gt;Android SDK emulator&lt;/span&gt; in &lt;span style="font-style:italic;"&gt;Eclipse&lt;/span&gt;. The emulator did not mount any SD-Card by default. In order to test the downloading code, the emulator must be set up with a SD-Card image file, like so (on my Linux system):&lt;br /&gt;&lt;code&gt;&lt;br /&gt;$ android-sdk/tools/mksdcard 64M ~/.android/avd/Android.2.1.avd/sdcard.img&lt;br /&gt;&lt;/code&gt; &lt;br /&gt;This created a 64MB image file (more than enough for the data) in a special &lt;span style="font-style:italic;"&gt;Android avd&lt;/span&gt; directory, so that it would be automatically mounted by the emulator.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Implement custom SQLite helper&lt;/h3&gt; Finally, I had to write my own custom version of the &lt;a href="http://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html"&gt;&lt;code&gt;SQLiteOpenHelper&lt;/code&gt;&lt;/a&gt; to access the database file from the SD-Card, because the standard one would only read from the default phone internal memory. Given that the reference data would be read-only, this custom class was a lot simpler than &lt;code&gt;SQLiteOpenHelper&lt;/code&gt; and only needed to open a read-only database connection. The code:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public abstract class ExternalStorageReadOnlyOpenHelper{&lt;br /&gt;     private SQLiteDatabase database;&lt;br /&gt;     private File dbFile;&lt;br /&gt;     private SQLiteDatabase.CursorFactory factory;&lt;br /&gt;&lt;br /&gt;     public ExternalStorageReadOnlyOpenHelper(&lt;br /&gt;         String dbFileName, SQLiteDatabase.CursorFactory factory) {&lt;br /&gt;        this.factory = factory;&lt;br /&gt;        &lt;br /&gt;        if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {&lt;br /&gt;            throw new AndroidRuntimeException(&lt;br /&gt;                "External storage (SD-Card) not mounted");&lt;br /&gt;        } &lt;br /&gt;        File appDbDir = new File(&lt;br /&gt;            Environment.getExternalStorageDirectory(),            &lt;br /&gt;            "Android/data/com.mycompany.myapp/db");&lt;br /&gt;        if (!appDbDir.exists()) {&lt;br /&gt;            appDbDir.mkdirs();&lt;br /&gt;        }&lt;br /&gt;        this.dbFile = new File(appDbDir, dbFileName);&lt;br /&gt;     }&lt;br /&gt;     &lt;br /&gt;     public boolean databaseFileExists() {&lt;br /&gt;        return dbFile.exists();&lt;br /&gt;     }&lt;br /&gt;     &lt;br /&gt;     private void open() {&lt;br /&gt;         if (dbFile.exists()) {&lt;br /&gt;             database = SQLiteDatabase.openDatabase(&lt;br /&gt;                 dbFile.getAbsolutePath(), &lt;br /&gt;                 factory, &lt;br /&gt;                 SQLiteDatabase.OPEN_READONLY);     &lt;br /&gt;         }&lt;br /&gt;     }&lt;br /&gt;        &lt;br /&gt;     public synchronized void close() {&lt;br /&gt;         if (database != null ) {&lt;br /&gt;            database.close();&lt;br /&gt;            database = null;&lt;br /&gt;        }&lt;br /&gt;     }&lt;br /&gt;&lt;br /&gt;     public synchronized SQLiteDatabase getReadableDatabase() {&lt;br /&gt;         return getDatabase();&lt;br /&gt;     }&lt;br /&gt;&lt;br /&gt;     private SQLiteDatabase getDatabase() {&lt;br /&gt;        if (database==null) {&lt;br /&gt;            open();&lt;br /&gt;        }&lt;br /&gt;        return database;&lt;br /&gt;     }         &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A concrete subclass of &lt;code&gt;ExternalStorageReadOnlyOpenHelper&lt;/code&gt; was created to query the reference data via the &lt;a href="http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html"&gt;&lt;code&gt;SQLiteDatabase&lt;/code&gt;&lt;/a&gt; object returned by the &lt;code&gt;getReadableDatabase()&lt;/code&gt; method.&lt;br /&gt;&lt;br /&gt;The &lt;code&gt;databaseFileExists()&lt;/code&gt; method allowed the main &lt;code&gt;Activity&lt;/code&gt; to check if the database file already existed to decide whether to initiate download.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;br /&gt;This final design had greatly improved the application in the following ways :&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The user only had to download a small apk file initially, greatly reducing the barrier to installation.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;The separate download step for the database file presented an opportunity to tell the user what was happening and to use Wi-Fi if available.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Most of the data resided on the SD-Card, where space was much more abundant.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;There was ever only one copy of the reference data on the phone, no redundant duplication.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;The main application code could be updated without having to download the reference data.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5156332309817509524-1625780591777546411?l=penguinman-techtalk.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://penguinman-techtalk.blogspot.com/feeds/1625780591777546411/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://penguinman-techtalk.blogspot.com/2010/08/loading-large-reference-database-in.html#comment-form' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5156332309817509524/posts/default/1625780591777546411'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5156332309817509524/posts/default/1625780591777546411'/><link rel='alternate' type='text/html' href='http://penguinman-techtalk.blogspot.com/2010/08/loading-large-reference-database-in.html' title='Loading large reference database in Android'/><author><name>penguinman</name><uri>http://www.blogger.com/profile/03293300286288413519</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp1.blogger.com/_2oGca8ZQVtc/R4WUQFuS1jI/AAAAAAAAAAM/YRVdoPal21U/S220/XRayPenguinAvatar.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_2oGca8ZQVtc/TFkShGt5j_I/AAAAAAAAAZ4/SAZ5iATQYNg/s72-c/android-db.jpg' height='72' width='72'/><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5156332309817509524.post-9030269004187717474</id><published>2010-05-27T20:48:00.032+10:00</published><updated>2010-06-01T07:16:34.067+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='psychology'/><category scheme='http://www.blogger.com/atom/ns#' term='user story'/><category scheme='http://www.blogger.com/atom/ns#' term='short-term reward'/><category scheme='http://www.blogger.com/atom/ns#' term='story size'/><title type='text'>Large User Story vs Human Psychology</title><content type='html'>Much have been written about the problems of oversized user stories. They are commonly indicative of too much uncertainty, usually over business requirements, but sometimes over certain technical aspects. While large stories (or epics) are acceptable during a high-level planning stage, they should be either simplified or broken down by the time they are scheduled within an iteration. Otherwise, they usually end up greatly exceeding their (very inaccurate) estimates, or even becoming blocked.&lt;br /&gt;&lt;br /&gt;As a software developer, I've been involved with a few such stories recently. In addition to the above-mentioned problems, I noticed another adverse side-effect. With each passing day on the same story, I became increasingly less motivated to observe good coding practices such as refactoring, cleaning up messy code and proper OO design. As the days dragged on, I became more tolerant of sloppy practices. I eventually &lt;i&gt;finished&lt;/i&gt; the story and handed over a piece of spaghetti code that I wasn't proud of. In hindsight, I could have done a lot more to improve code quality. &lt;br /&gt;&lt;br /&gt;Thinking back, I realized that this same behaviour manifested itself many times before in the past. Perhaps, I might just assume that I was a lazy bum, if not for the fact that I was practising pair-programming, and the same tendency was also apparent in my pairing partners (some more resistant than others). Maybe it was just the long hours and looming deadlines. However, my experience tells me that doing multiple smaller consecutive stories, while they may add up to the same volume of work as a giant story, does not lead to this behaviour.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 1px solid #DDDDDD; float: left; padding: 5px; margin: 0 5px 5px 0; text-align: center;"&gt;&lt;img style="width: 250px; height: 320px;" src="http://1.bp.blogspot.com/_2oGca8ZQVtc/TAO_8umhS8I/AAAAAAAAAWQ/raTIr595-F4/s320/psychology-image.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5477432621835307970" /&gt;&lt;div style="clear:both; font-size: 60%;"&gt;Image from: weber.edu&lt;/div&gt;&lt;/div&gt;This leads me to speculate that there is a psychological explanation. Research has shown that the human brain has two regions that &lt;span style="font-weight:bold;"&gt;compete&lt;/span&gt; to form a decision when presented with a choice between a small short-term reward and a longer-term goal (larger reward). The more emotionally driven region of the brain seeks the short-term reward while the rational region tells us to hold-out for the overall better outcome. Our brain battles itself to a decision. As professional software developers, we constantly have to make a similar decision :- should we take a short-cut to deliver a piece of work now, or refactor/write more tests/clean up so that the overall code quality improves in the long run? &lt;br /&gt;&lt;br /&gt;It is likely that by breaking up a large body of work into many small discrete stories, the completion of each story provides an emotionally satisfying reward in a short period of time, even if extra effort/time has been added to ensure good quality. This extra effort/time is usually at least proportional to the original estimated size of the story, but may cost even more if the story gets so large that it touches many interdependent parts of a complex system. &lt;br /&gt;&lt;br /&gt;In other words, a small story usually touches a small area of the code base, hence its parts are easier to visualize in one's head, and thus presents only a small mental barrier to keeping it clean. Conversely, a massive story that encroaches on a myriad of different moving parts becomes hard to visualize. Soon, problem areas stack up beyond our ability to keep track of them in our heads. On top of that, the uncertainties inherent in a large story may reveal themselves to be time-sinks. Before long, the extra effort required to deliver quality becomes a mountain of hurdles. Having spent most of our time and energy just getting to code to work, with no psychological reward from completing anything yet, it is no wonder that we become disinclined to continue. &lt;br /&gt;&lt;br /&gt;In conclusion, &lt;span style="font-weight:bold;"&gt;large user stories work against human psychology&lt;/span&gt; for the desired long-term goal of good quality code. Small stories are more satisfying due to frequent emotional rewards, at the same time contributing towards the greater goal. &lt;br /&gt;&lt;br /&gt;It is not always possible to foresee how big a story can become at the start, therefore, developers should be given the freedom to split up stories while they are being developed. Personally, I think a story should not take more than 2 to 3 days. If it looks bigger than this, split it. This I endeavor to do more of in the future, with the hope of always delivering code I can be proud of.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5156332309817509524-9030269004187717474?l=penguinman-techtalk.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://penguinman-techtalk.blogspot.com/feeds/9030269004187717474/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://penguinman-techtalk.blogspot.com/2010/05/large-user-story-vs-human-psychology.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5156332309817509524/posts/default/9030269004187717474'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5156332309817509524/posts/default/9030269004187717474'/><link rel='alternate' type='text/html' href='http://penguinman-techtalk.blogspot.com/2010/05/large-user-story-vs-human-psychology.html' title='Large User Story vs Human Psychology'/><author><name>penguinman</name><uri>http://www.blogger.com/profile/03293300286288413519</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp1.blogger.com/_2oGca8ZQVtc/R4WUQFuS1jI/AAAAAAAAAAM/YRVdoPal21U/S220/XRayPenguinAvatar.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_2oGca8ZQVtc/TAO_8umhS8I/AAAAAAAAAWQ/raTIr595-F4/s72-c/psychology-image.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5156332309817509524.post-6480773915044059103</id><published>2009-11-02T06:48:00.011+11:00</published><updated>2009-11-04T12:41:39.359+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='env.rhino.js'/><category scheme='http://www.blogger.com/atom/ns#' term='RhinoUnit'/><category scheme='http://www.blogger.com/atom/ns#' term='env.js'/><category scheme='http://www.blogger.com/atom/ns#' term='unit test'/><category scheme='http://www.blogger.com/atom/ns#' term='jQuery'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Testing jQuery with env.js + RhinoUnit</title><content type='html'>The previous (Web application) project I was on started adopting &lt;a href="http://jquery.com"&gt;jQuery&lt;/a&gt; to implement more client-side browser behaviour. We were already using &lt;a href="http://code.google.com/p/rhinounit/"&gt;RhinoUnit&lt;/a&gt; for testing some generic Javascript logic, but jQuery required access to the browser DOM. Hence, &lt;a href="http://github.com/thatcher/env-js"&gt;env.js&lt;/a&gt; was used to provided a DOM to RhinoUnit. This combination would be very quick due to RhinoUnit running headlessly and not relying on a browser, which was perfect for TDD. Getting these three pieces to work together properly took some work, as described below.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Versions&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;jQuery 1.3.2&lt;/li&gt;&lt;li&gt;env-js.1.0.rc7, using env.rhino.js&lt;/li&gt;&lt;li&gt;RhinoUnit 1.2.1&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Replaced self&lt;/span&gt;&lt;br /&gt;As mentioned in &lt;a href="http://www.randomfocus.net/2009/05/rhinounit-with-envjs.html"&gt;Adam Scott's blog&lt;/a&gt;, references to &lt;code&gt;self&lt;/code&gt; in RhinoUnit needed to be replaced. So at the top of the &lt;i&gt;rhinoUnitAnt.js&lt;/i&gt;, I added this:&lt;br /&gt;&lt;code&gt;var rhinoUnitSelf = self;&lt;/code&gt;&lt;br /&gt;All references to &lt;code&gt;self&lt;/code&gt; below this were replaced with references to &lt;code&gt;rhinoUnitSelf&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Replaced print&lt;/span&gt;&lt;br /&gt;Adam Scott's blog also mentioned the need to replace calls to &lt;code&gt;print&lt;/code&gt; with &lt;code&gt;self.log&lt;/code&gt; function. Specifically, reimplemented &lt;code&gt;$env.log&lt;/code&gt; in &lt;i&gt;env.rhino.js&lt;/i&gt; like so:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;$env.log = function(msg, level){&lt;br /&gt;    rhinoUnitSelf.log(' '+ (level?level:'LOG') + ':\t['+ new Date()+"] {ENVJS} "+msg);&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt; &lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Implemented load&lt;/span&gt;&lt;br /&gt;For some strange reason, env.js relies on a &lt;code&gt;load&lt;/code&gt; function that could not be found. The solution was just to implement it using RhinoUnit's &lt;code&gt;loadFile&lt;/code&gt;. The following was added to the top of &lt;i&gt;env.rhino.js&lt;/i&gt;:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;load = function(x) {&lt;br /&gt; eval(loadFile(x));&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Ignored global variables&lt;/span&gt;&lt;br /&gt;jQuery and our unit tests created a lot of global variables that RhinoUnit didn't like. Instead of configuring RhinoUnit to ignore a massive list of global variables, I decided to simply remove the code that checked for this. Specifically, reimplemented &lt;code&gt;ignoreGlobalVariableName&lt;/code&gt; in &lt;i&gt;rhinoUnitAnt.js&lt;/i&gt; as such:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;function ignoreGlobalVariableName(name) {&lt;br /&gt;    return true;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Cleanup after tests&lt;/span&gt;&lt;br /&gt;At this stage, our unit tests could run individually, but they failed when executed together  (consecutively, from Ant). This was because the global variables that were created during the first test were not cleaned up and they corrupted the environment for all subsequent tests. In order to fix this, I modified the end of the &lt;code&gt;runTest(file)&lt;/code&gt; function in &lt;i&gt;rhinoUnitAnt.js&lt;/i&gt; so that global variables created in one testcase (test file) were cleaned up prior to running the next testcase.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;/*****  ADDED to remember global variables that existed prior to each test file *****/&lt;br /&gt;    var origGlobalVars = {};&lt;br /&gt;    var varName;&lt;br /&gt;    for (varName in this) {&lt;br /&gt;        origGlobalVars[varName] = true;&lt;br /&gt;    }&lt;br /&gt;/************************************************************************************/&lt;br /&gt;&lt;br /&gt;    eval(loadFile(file));&lt;br /&gt;&lt;br /&gt;    var testCount = 0;&lt;br /&gt;    var failingTests = 0;&lt;br /&gt;    var erroringTests = 0;&lt;br /&gt;&lt;br /&gt;    executeTestCases(test, test.setUp, test.tearDown);&lt;br /&gt;&lt;br /&gt;    if (testCount === 0) {&lt;br /&gt;        erroringTests += 1;&lt;br /&gt;        testfailed = true;&lt;br /&gt;        failingTestMessage(file, "No tests defined");&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    rhinoUnitSelf.log("Tests run: " + testCount + ", Failures: " + failingTests + ", Errors: " + erroringTests);&lt;br /&gt;    rhinoUnitSelf.log("");&lt;br /&gt;&lt;br /&gt;/******  ADDED to remove only those global variables that have been &lt;br /&gt;         added by the test file, but not those that existed before.  ******/&lt;br /&gt;    for (varName in this) {&lt;br /&gt;        if (origGlobalVars[varName] != true) {&lt;br /&gt;            delete this[varName];&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;/*********************************************************************/&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;After these changes, our jQuery unit tests ran perfectly, allowing us to do TDD for our jQuery code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5156332309817509524-6480773915044059103?l=penguinman-techtalk.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://penguinman-techtalk.blogspot.com/feeds/6480773915044059103/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://penguinman-techtalk.blogspot.com/2009/11/testing-jquery-with-envjs-rhinounit.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5156332309817509524/posts/default/6480773915044059103'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5156332309817509524/posts/default/6480773915044059103'/><link rel='alternate' type='text/html' href='http://penguinman-techtalk.blogspot.com/2009/11/testing-jquery-with-envjs-rhinounit.html' title='Testing jQuery with env.js + RhinoUnit'/><author><name>penguinman</name><uri>http://www.blogger.com/profile/03293300286288413519</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp1.blogger.com/_2oGca8ZQVtc/R4WUQFuS1jI/AAAAAAAAAAM/YRVdoPal21U/S220/XRayPenguinAvatar.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5156332309817509524.post-2216294956317446889</id><published>2009-03-26T18:00:00.036+11:00</published><updated>2009-04-09T11:36:11.184+10:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='statistics'/><category scheme='http://www.blogger.com/atom/ns#' term='remote server'/><category scheme='http://www.blogger.com/atom/ns#' term='snmp'/><category scheme='http://www.blogger.com/atom/ns#' term='servlet'/><category scheme='http://www.blogger.com/atom/ns#' term='cacti'/><category scheme='http://www.blogger.com/atom/ns#' term='graphing'/><title type='text'>Cacti : Graphing remote service WITHOUT using SNMP</title><content type='html'>&lt;h3&gt;What is Cacti&lt;/h3&gt;&lt;br /&gt;&lt;a href="http://www.cacti.net"&gt;Cacti&lt;/a&gt; is a popular Web-based tool for generating graphs of various data/statistics from remote servers. It provides default "templates" for generating graphs of CPU load, processes, memory, etc out-of-the-box, mainly retrieving these data from remote machines via &lt;a href="http://www.net-snmp.org"&gt;SNMP (Simple Network Management Protocol)&lt;/a&gt;. Cacti can be set up to graph custom data, again using SNMP by default. In fact, most of the instructions available online assume that Cacti talks SNMP to remote machines.&lt;br /&gt;&lt;br /&gt;This blog is based on Cacti version &lt;b&gt;0.8.7d&lt;/b&gt;, running on a Linux machine.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;The problem with SNMP&lt;/h3&gt;&lt;br /&gt;However, I find SNMP to be &lt;a href="http://www.rane.com/note161.html"&gt;very complicated&lt;/a&gt; to set up for anything more complex than a single value data. Personally, I find SNMP to be overkill and far too difficult to manage, especially when it comes to setting up a custom SNMP table to group data in a way that can be traversed by Cacti.&lt;br /&gt; &lt;br /&gt;&lt;h3&gt;Alternative to SNMP&lt;/h3&gt;&lt;br /&gt;This blog shows how Cacti can be used to retrieve data, via HTTP, from a URL that points to a "Web service" (not the heavy SOAP kind) that returns data in a simple text format. This can be implemented using JSP, PHP, a simple Java servlet or just any Web technology. All it needs to do is to return in its response the data in the following textual format:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;fieldName1:fieldValue1 fieldName2:fieldValue2 fieldName3:fieldValue3 ... &lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Example&lt;/h3&gt;&lt;br /&gt;Lets assume I'm hosting a Java Web application, and I want to graph the following:&lt;br /&gt;- The number of requests that generated successful responses.&lt;br /&gt;- The number of requests that generated errors.&lt;br /&gt;&lt;br /&gt;Two things are required on the Java application side:&lt;br /&gt;- Some sort of filter/interceptor to capture these two types of request.&lt;br /&gt;- A servlet to count the number of these requests and return a response in the desired format. This servlet will reset its counters after sending each response, so that each time it returns the count since the last response. The response content type is set to &lt;code&gt;text/plain&lt;/code&gt; and the content looks something like:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;successCount:1623 errorCount:23&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;This servlet is deployed on the same Web container as the main Web application, and mapped to the URL:&lt;br /&gt;&lt;code&gt;http://remoteserver:8080/myapp/statistics&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Cacti Configuration&lt;/h3&gt;&lt;br /&gt;&lt;h4&gt;Poller Settings&lt;/h4&gt;&lt;br /&gt;Firstly, tell Cacti to simply use Ping to detect hosts for polling. Click on &lt;i&gt;Settings&lt;/i&gt; on the left bar, then click on the &lt;i&gt;Poller&lt;/i&gt; tab and change &lt;i&gt;Downed Host Detection&lt;/i&gt; to just &lt;i&gt;Ping&lt;/i&gt;, as shown below:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_2oGca8ZQVtc/Sdz9S-bfinI/AAAAAAAAAF8/LOKCjnlnKA0/s1600-h/cacti-settings-poller.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 246px;" src="http://1.bp.blogspot.com/_2oGca8ZQVtc/Sdz9S-bfinI/AAAAAAAAAF8/LOKCjnlnKA0/s320/cacti-settings-poller.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5322407362082867826" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Device&lt;/h4&gt;&lt;br /&gt;After that, set up a device to point to the server that is hosting the Web application. Assume it is reachable by name &lt;code&gt;remoteserver&lt;/code&gt;. Create a device of type &lt;i&gt;None&lt;/i&gt; as shown below, meaning Cacti will use ping to detect the server. &lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_2oGca8ZQVtc/Sd1QotitQ2I/AAAAAAAAAGE/p_GXNwZYUA0/s1600-h/cacti-device.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 175px;" src="http://3.bp.blogspot.com/_2oGca8ZQVtc/Sd1QotitQ2I/AAAAAAAAAGE/p_GXNwZYUA0/s320/cacti-device.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5322498994971951970" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Note:&lt;/b&gt; This version of Cacti has a bug (at least on my Firefox browser) where it tries to validate that the &lt;i&gt;SNMP Version 3&lt;/i&gt; passwords match even when SNMP is set to &lt;i&gt;Not In Use&lt;/i&gt;. To work around this, first select &lt;i&gt;SNMP Version 3&lt;/i&gt;, blank out both passwords, then select &lt;i&gt;Not In Use&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Data Input Method&lt;/h4&gt;&lt;br /&gt;A Data Input Method is set up to tell Cacti to retrieve the data from the servlet (using wget), and map the field names in the response text to fields that Cacti understands. Refer to screenshot below:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_2oGca8ZQVtc/Sc_Ov8Q_BsI/AAAAAAAAAE8/2FGRsb0kDhM/s1600-h/cacti-data-input-method.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 126px;" src="http://4.bp.blogspot.com/_2oGca8ZQVtc/Sc_Ov8Q_BsI/AAAAAAAAAE8/2FGRsb0kDhM/s320/cacti-data-input-method.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5318697007974385346" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Name this Data Input Method as &lt;code&gt;RemoteServerInputMethod&lt;/code&gt;. Select &lt;i&gt;Script/Command&lt;/i&gt; as the &lt;i&gt;Input Type&lt;/i&gt;, and type the following in the &lt;i&gt;Input String&lt;/i&gt; :&lt;br /&gt;&lt;code&gt;wget --quiet --no-cache -O - http://&amp;lt;hostname&amp;gt;:&amp;lt;data_port&amp;gt;/myapp/statistics&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Create &lt;i&gt;hostname&lt;/i&gt; and &lt;i&gt;data_port&lt;/i&gt; input fields, that are used to pass in values to the &amp;lt;hostname&amp;gt; and &amp;lt;data_port&amp;gt; parameters in the script command.&lt;br /&gt;&lt;br /&gt;Create &lt;i&gt;successCount&lt;/i&gt; and &lt;i&gt;errorCount&lt;/i&gt; output fields, that are mapped to the field names in the response text. Make sure these output field names exactly match those in the servlet response text.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Data Template&lt;/h4&gt;&lt;br /&gt;The Data Input Method is used to create a Data Template, as shown below:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_2oGca8ZQVtc/Sc_O_Nhj27I/AAAAAAAAAFM/ljyvljXNkDQ/s1600-h/cacti-data-template.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 235px;" src="http://1.bp.blogspot.com/_2oGca8ZQVtc/Sc_O_Nhj27I/AAAAAAAAAFM/ljyvljXNkDQ/s320/cacti-data-template.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5318697270305348530" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Name this Data Template as &lt;code&gt;RemoteServerStatisticsDataTemplate&lt;/code&gt;. Name the &lt;i&gt;Data Source&lt;/i&gt; as &lt;code&gt;RemoteServerStatisticsDataSource&lt;/code&gt;, this will automatically become the data source name (see later). &lt;br /&gt;&lt;br /&gt;Create a Data Source Item to map to each of the data fields, i.e. &lt;i&gt;successCount&lt;/i&gt; and &lt;i&gt;errorCount&lt;/i&gt;. Most of the settings here can stick to the defaults. The important part is to make sure that the &lt;i&gt;Output Field&lt;/i&gt; selectors are mapped to the correct fields.&lt;br /&gt;&lt;br /&gt;Its better to tick the checkbox under the &lt;i&gt;Port on server Custom Data&lt;/i&gt; to tell Cacti to assign the port from the data source, so that we don't have to hardcode 8080 in the Data Template. &lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Data Source&lt;/h4&gt;&lt;br /&gt;Create a Data Source that connects the Data Template with the Host Device that were configured earlier. Select appropriate options for these two drop-down selectors. Do not change the &lt;i&gt;Data Source Path&lt;/i&gt;. Enter &lt;code&gt;8080&lt;/code&gt; as the &lt;i&gt;Port on server&lt;/i&gt;.   &lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_2oGca8ZQVtc/Sc_O20wPcEI/AAAAAAAAAFE/myH5frhhnYI/s1600-h/cacti-data-source.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 94px;" src="http://4.bp.blogspot.com/_2oGca8ZQVtc/Sc_O20wPcEI/AAAAAAAAAFE/myH5frhhnYI/s320/cacti-data-source.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5318697126217084994" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This screen creates a Data Source that automatically gets the name as specified in the Data Template screen before.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Graph Template&lt;/h4&gt;&lt;br /&gt;Set up a Graph Template to tell Cacti how to plot the data in the graph. Name it &lt;code&gt;RemoteServerStatisticsGraphTemplate&lt;/code&gt;, and give the graph a descriptive &lt;i&gt;Title&lt;/i&gt;. All other fields below the &lt;i&gt;Title&lt;/i&gt; can be left in their default values. Create two &lt;i&gt;Graph Template Item&lt;/i&gt;s as shown in the screenshot below. &lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_2oGca8ZQVtc/Sc_PYFM9KEI/AAAAAAAAAFc/x4ZcJl6BPIU/s1600-h/cacti-graph-template.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 102px;" src="http://3.bp.blogspot.com/_2oGca8ZQVtc/Sc_PYFM9KEI/AAAAAAAAAFc/x4ZcJl6BPIU/s320/cacti-graph-template.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5318697697568172098" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Note that creating a &lt;i&gt;Graph Template Item&lt;/i&gt; will automatically create a corresponding &lt;i&gt;Graph Item Input&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;The screenshot below shows the screen for creating a Graph Template Item. Simply choose the matching &lt;i&gt;Data Source&lt;/i&gt; for the field, and enter a descriptive &lt;i&gt;Text Format&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_2oGca8ZQVtc/Sc_PgHCucHI/AAAAAAAAAFk/5oOsUhv36xs/s1600-h/cacti-graph-template-item.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 119px;" src="http://4.bp.blogspot.com/_2oGca8ZQVtc/Sc_PgHCucHI/AAAAAAAAAFk/5oOsUhv36xs/s320/cacti-graph-template-item.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5318697835501088882" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Graph Management&lt;/h4&gt;&lt;br /&gt;Enter Graph Management to create an association between Graph Template, Host Device and the Data Sources. The screenshot below should be self-explanatory.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_2oGca8ZQVtc/Sc_PUMat5bI/AAAAAAAAAFU/jTu3G86eudM/s1600-h/cacti-graph-management.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 98px;" src="http://3.bp.blogspot.com/_2oGca8ZQVtc/Sc_PUMat5bI/AAAAAAAAAFU/jTu3G86eudM/s320/cacti-graph-management.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5318697630785463730" /&gt;&lt;/a&gt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Graph Tree&lt;/h4&gt;&lt;br /&gt;Finally, enter Graph Tree to place the graph in the hierarchical tree. This is quite straightforward. Create a Tree Item of type &lt;i&gt;Host&lt;/i&gt;, and point it to the Host.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_2oGca8ZQVtc/Sc_PmIZoSWI/AAAAAAAAAFs/mTTpK2pOWMg/s1600-h/cacti-graph-tree-item.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 66px;" src="http://2.bp.blogspot.com/_2oGca8ZQVtc/Sc_PmIZoSWI/AAAAAAAAAFs/mTTpK2pOWMg/s320/cacti-graph-tree-item.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5318697938944805218" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The new Tree Item will appear like so in the Graph Tree:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_2oGca8ZQVtc/Sc_PpgbkEMI/AAAAAAAAAF0/OUvr_-Uc6M0/s1600-h/cacti-graph-trees.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 74px;" src="http://4.bp.blogspot.com/_2oGca8ZQVtc/Sc_PpgbkEMI/AAAAAAAAAF0/OUvr_-Uc6M0/s320/cacti-graph-trees.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5318697996934975682" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;DONE!&lt;/h3&gt;&lt;br /&gt;Finally, its all done. Just click on the Graph tab, drill down the tree and see the graph of successful and error request counts.&lt;br /&gt;&lt;br /&gt;&lt;hr /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5156332309817509524-2216294956317446889?l=penguinman-techtalk.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://penguinman-techtalk.blogspot.com/feeds/2216294956317446889/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://penguinman-techtalk.blogspot.com/2009/03/cacti-graphing-remote-service-without.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5156332309817509524/posts/default/2216294956317446889'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5156332309817509524/posts/default/2216294956317446889'/><link rel='alternate' type='text/html' href='http://penguinman-techtalk.blogspot.com/2009/03/cacti-graphing-remote-service-without.html' title='Cacti : Graphing remote service WITHOUT using SNMP'/><author><name>penguinman</name><uri>http://www.blogger.com/profile/03293300286288413519</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp1.blogger.com/_2oGca8ZQVtc/R4WUQFuS1jI/AAAAAAAAAAM/YRVdoPal21U/S220/XRayPenguinAvatar.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_2oGca8ZQVtc/Sdz9S-bfinI/AAAAAAAAAF8/LOKCjnlnKA0/s72-c/cacti-settings-poller.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5156332309817509524.post-6423679191715845309</id><published>2009-02-26T11:58:00.001+11:00</published><updated>2009-03-30T16:28:50.528+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sqlplus'/><category scheme='http://www.blogger.com/atom/ns#' term='connection string'/><category scheme='http://www.blogger.com/atom/ns#' term='remote database'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL*Plus'/><category scheme='http://www.blogger.com/atom/ns#' term='oracle'/><title type='text'>SQL*Plus connection to remote Oracle database</title><content type='html'>&lt;i&gt;SQL*Plus&lt;/i&gt; is a very handy command line tool when you want to quickly access an Oracle database or execute SQL statements from scripts, e.g. BASH scripts. However, getting it to connect to a remote Oracle database server in a script proved to be quite a challenge. This blog documents how to write the connection string in various cases.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Local database&lt;/h3&gt;&lt;br /&gt;Connecting to a local database is trivial, just use:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;$ sqlplus dbUser/dbPassword@dbSid&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Remote database from command line&lt;/h3&gt;&lt;br /&gt;Here's the nasty syntax for connecting to a remote database using its SID:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;$ sqlplus dbUser/dbPassword@'(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=remoteServer)(PORT=1521)))(CONNECT_DATA=(SID=dbSid)))'&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;You can also connect using a SERVICE_NAME instead of SID.&lt;br /&gt;Note that the single-quotes are needed to preserve the brackets. &lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Remote database from a BASH script&lt;/h3&gt;&lt;br /&gt;I needed to write a script that called &lt;i&gt;SQL*Plus&lt;/i&gt; several times. In order to make it maintainable, the username, password and the part after the @ were specified as environment variables. Unfortunately, there did not seem to be any obvious way of setting the value of the environment variable so that the single-quotes were properly sent to the sqlplus command at run time. I had to explicitly escape each bracket with a backslash, like so:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;DB_CONNECTION=\(DESCRIPTION=\(ADDRESS_LIST=\(ADDRESS=\(PROTOCOL=TCP\)\(HOST=remoteServer\)\(PORT=1521\)\)\)\(CONNECT_DATA=\(SID=dbSid\)\)\)&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Because this script was part of a Java project, I subsequently moved this value to a Java properties file. This means every backslash had to be escaped with another backslash to prevent Java from interpreting it. The entry in the Java properties file:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;db.connection = \\(DESCRIPTION=\\(ADDRESS_LIST=\\(ADDRESS=\\(PROTOCOL=TCP\\)\\(HOST=remoteServer\\)\\(PORT=1521\\)\\)\\)\\(CONNECT_DATA=\\(SID=dbSid\\)\\)\\)&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;(I know I could have just used JDBC, but there was a good reason why I had to use &lt;i&gt;SQL*Plus&lt;/i&gt; for this Java project.)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Define a local service name to a remote server&lt;/h3&gt;&lt;br /&gt;An alternative to using the big ugly connection string is to define a local service name in the local tnsnames.ora that references the remote instance. Add the following:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;DB_LOCAL_NAME =&lt;br /&gt;  (DESCRIPTION =&lt;br /&gt;    (ADDRESS = (PROTOCOL= TCP)(Host= remoteServer)(Port= 1521))&lt;br /&gt;    (CONNECT_DATA = (SID = dbSid))&lt;br /&gt;  )&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;to&lt;br /&gt;&lt;br /&gt;&lt;code&gt;${ORACLE_HOME}/server/network/admin/tnsnames.ora&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Connecting to the remote database is simply:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;$ sqlplus dbUser/dbPassword@DB_LOCAL_NAME&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Of course, this solution has a few drawbacks (enough to dissuade me from using it). &lt;br /&gt;- Need write permission to the tnsnames.ora.&lt;br /&gt;- The application relies of custom entries in tnsnames.ora, which must be maintained together with the application code. &lt;br /&gt;- Every environment (e.g. development, staging, UAT, production) in which the application is deployed to will need to have its tnsnames.ora modified and maintained. &lt;br /&gt;&lt;br /&gt;&lt;hr /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5156332309817509524-6423679191715845309?l=penguinman-techtalk.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://penguinman-techtalk.blogspot.com/feeds/6423679191715845309/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://penguinman-techtalk.blogspot.com/2009/02/sqlplus-connection-to-remote-oracle.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5156332309817509524/posts/default/6423679191715845309'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5156332309817509524/posts/default/6423679191715845309'/><link rel='alternate' type='text/html' href='http://penguinman-techtalk.blogspot.com/2009/02/sqlplus-connection-to-remote-oracle.html' title='SQL*Plus connection to remote Oracle database'/><author><name>penguinman</name><uri>http://www.blogger.com/profile/03293300286288413519</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp1.blogger.com/_2oGca8ZQVtc/R4WUQFuS1jI/AAAAAAAAAAM/YRVdoPal21U/S220/XRayPenguinAvatar.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5156332309817509524.post-6999727653645148548</id><published>2009-02-20T11:30:00.000+11:00</published><updated>2009-02-26T11:58:06.571+11:00</updated><title type='text'>Save the Net</title><content type='html'>&lt;div&gt;&lt;object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,28,0" width="300" height="250"&gt;&lt;param name="movie" value="http://www.getup.org.au/flash/widget.swf"&gt;&lt;param name="quality" value="high"&gt;&lt;embed src="http://www.getup.org.au/flash/widget.swf" quality="high" pluginspage="http://www.adobe.com/shockwave/download/download.cgi?P1_Prod_Version=ShockwaveFlash" type="application/x-shockwave-flash" width="300" height="250"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;hr /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5156332309817509524-6999727653645148548?l=penguinman-techtalk.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://penguinman-techtalk.blogspot.com/feeds/6999727653645148548/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://penguinman-techtalk.blogspot.com/2009/02/save-net.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5156332309817509524/posts/default/6999727653645148548'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5156332309817509524/posts/default/6999727653645148548'/><link rel='alternate' type='text/html' href='http://penguinman-techtalk.blogspot.com/2009/02/save-net.html' title='Save the Net'/><author><name>penguinman</name><uri>http://www.blogger.com/profile/03293300286288413519</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp1.blogger.com/_2oGca8ZQVtc/R4WUQFuS1jI/AAAAAAAAAAM/YRVdoPal21U/S220/XRayPenguinAvatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5156332309817509524.post-7526634604335908202</id><published>2009-01-09T17:22:00.000+11:00</published><updated>2009-01-20T10:39:47.805+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PFile'/><category scheme='http://www.blogger.com/atom/ns#' term='integration test'/><category scheme='http://www.blogger.com/atom/ns#' term='SYSDATE'/><category scheme='http://www.blogger.com/atom/ns#' term='fixed_date'/><category scheme='http://www.blogger.com/atom/ns#' term='SPFile'/><category scheme='http://www.blogger.com/atom/ns#' term='oracle'/><title type='text'>Date sensitive integration testing of database code with Oracle</title><content type='html'>&lt;span style="font-size:78%;"&gt;&lt;b&gt;Note:&lt;/b&gt;&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-size:78%;"&gt;Commands starting with &lt;code&gt;$&lt;/code&gt; are to be entered in a shell, e.g. BASH.&lt;/span&gt;&lt;/li&gt;&lt;span style="font-size:78%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;li&gt;&lt;span style="font-size:78%;"&gt;Commands starting with &lt;code&gt;SQL&gt;&lt;/code&gt; are to be entered in a database client, e.g. SQLPlus or JDBC code&lt;/span&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;h3&gt;Scenario&lt;/h3&gt;&lt;br /&gt;Lately, I've been working with a lot of database code, mostly packaged as stored procedures, running on &lt;i&gt;Oracle 10g XE&lt;/i&gt;. These stored procedures are tested using a set of automated integration tests written in Java (JUnit + DBUnit). Everything was fine until one day, I needed to implement a logic that filters out data based on whether a date field stores a date within a certain period of time. The SQL for this was quite trivial, for example:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;SELECT ... WHERE table1.the_date_field &gt; ADD_MONTHS(SYSDATE, -6)&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;This example would filter out all results with &lt;i&gt;the_date_field&lt;/i&gt; storing a date older than 6 months ago.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;The Problem&lt;/h3&gt;The problem arose when I needed to write automated tests for this. The tests loaded up a set of hardcoded test data fixture (using DBUnit). The test data would have hardcoded date values. Obviously, these tests would give different results over time because SYSDATE would return the current system time by default.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;The Solution(s)&lt;/h3&gt;One possible solution would be to dynamically inject the dates into the test data when the tests were executed. However, this would require a lot of work because of the quantity and spread of the dates. I would need to convert existing hardcoded dates into offsets from SYSDATE, then write some code to perform the injection at runtime.&lt;br /&gt;&lt;br /&gt;Given this, I chose the reverse approach :- make SYSDATE return a fixed value.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Stopping time&lt;/h4&gt;Luckily, Oracle provided a way to let me do just this.&lt;br /&gt;Firstly, I had to login to the database as a SYSDBA and grant my Oracle user the &lt;code&gt;ALTER SYSTEM&lt;/code&gt;  system privilege.&lt;br /&gt;Now, I could invoke the following SQL in the set-up code of the JUnit tests:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;SQL&gt; alter system set fixed_date = '01-APR-2005'&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;This would make SYSDATE always return April 1st, 2005. All the test data could now be measured relative to this date, and the tests would not break no matter when they were run.&lt;br /&gt;&lt;br /&gt;The tear-down code of the JUnit tests would invoke:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;SQL&gt; alter system set fixed_date = 'none'&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;to revert SYSDATE back to its default behaviour.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;PFile and SPFile&lt;/h4&gt;However, when I tried to restart Oracle server, it failed to start up. After a few hours, I found out why. Oracle by default stored parameter settings in a binary file format called SPFile. Any changes made with &lt;code&gt;ALTER SYSTEM&lt;/code&gt; were always persisted to this file, so that when Oracle was restarted, it tried to load them again. For some reason (a bug IMHO), Oracle could not load the &lt;cite&gt;fixed_date&lt;/cite&gt; value of 'none', it simply died.&lt;br /&gt;&lt;br /&gt;The workaround was to change to a different file format called PFile. PFile is a normal text file that could be editted, and unlike SPFile, Oracle would not persist any parameter changes to it. In my opinion, PFile is a better choice for a development or automated testing database, where changes made during tests should not be persisted or interfere each other. To convert from SPFile to PFile, first login as a SYSDBA:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;$ $ORACLE_HOME/bin/sqlplus sys as sysdba&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;then execute:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;SQL&gt; create pfile from spfile;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Then shut down Oracle server, and remove the SPFile. The SPFile name has the following format: spfileSID.ora, where SID is the database SID. I was developing on a Ubuntu machine and my SID was XE. Hence, I ran this:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;$ rm $ORACLE_HOME/dbs/spfileXE.ora&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The PFile name has the format initSID.ora, so it was initXE.ora on my machine. Edit this file with a text editor and delete the line:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;*.fixed_date='NONE'&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Finally, restart Oracle.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Limitations&lt;/h3&gt;&lt;br /&gt;I found that when SYSDATE was fixed to a hardcoded value, jobs could not be scheduled using &lt;code&gt;DBMS_JOB&lt;/code&gt; functions. &lt;code&gt;DBMS_JOB.SUBMIT&lt;/code&gt; did not seem to work at all. Therefore, I can't yet think of a way of both freezing time and testing any code that rely on scheduled jobs.&lt;br /&gt;&lt;br /&gt;&lt;hr /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5156332309817509524-7526634604335908202?l=penguinman-techtalk.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://penguinman-techtalk.blogspot.com/feeds/7526634604335908202/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://penguinman-techtalk.blogspot.com/2009/01/date-sensitive-integration-testing-of.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5156332309817509524/posts/default/7526634604335908202'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5156332309817509524/posts/default/7526634604335908202'/><link rel='alternate' type='text/html' href='http://penguinman-techtalk.blogspot.com/2009/01/date-sensitive-integration-testing-of.html' title='Date sensitive integration testing of database code with Oracle'/><author><name>penguinman</name><uri>http://www.blogger.com/profile/03293300286288413519</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp1.blogger.com/_2oGca8ZQVtc/R4WUQFuS1jI/AAAAAAAAAAM/YRVdoPal21U/S220/XRayPenguinAvatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5156332309817509524.post-4870972087220981551</id><published>2008-12-12T23:49:00.002+11:00</published><updated>2009-02-26T13:14:12.417+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='laptop'/><category scheme='http://www.blogger.com/atom/ns#' term='Toshiba Portege M800'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='mandriva 2009'/><title type='text'>Mandriva 2009 on Toshiba Portege M800</title><content type='html'>&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_2oGca8ZQVtc/SUJeWG6kWII/AAAAAAAAAD0/pv91nFSJWBE/s1600-h/snapshot.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 200px;" src="http://1.bp.blogspot.com/_2oGca8ZQVtc/SUJeWG6kWII/AAAAAAAAAD0/pv91nFSJWBE/s320/snapshot.jpg" alt="" id="BLOGGER_PHOTO_ID_5278885447138039938" border="0" /&gt;&lt;/a&gt;&lt;span style="font-size:78%;"&gt;(Screenshot of KDE 4 desktop with Dolphin file manager, photo and desktop widgets)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;I've just installed the newly released &lt;span style="font-style: italic;"&gt;Mandriva 2009.0 Powerpack&lt;/span&gt; on a company supplied &lt;span style="font-style: italic;"&gt;Toshiba Portege M800&lt;/span&gt;. Almost everything worked out of the box... &lt;span style="font-weight: bold;"&gt;almost&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;The following required some tweaking:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Video Playback&lt;/span&gt;&lt;br /&gt;I did not like &lt;span style="font-style: italic;"&gt;DragonPlayer&lt;/span&gt; that was configured by the installer. so the first thing I did was install &lt;span style="font-style: italic;"&gt;MPlayer&lt;/span&gt; (my favourite video player that plays everything) from &lt;a href="http://www.penguinliberationfront.com"&gt;PLF&lt;/a&gt;, together with all the popular codecs. Initially, my video did not play. After reading the &lt;a href="http://wiki.mandriva.com/en/2009.0_Errata"&gt;Mandriva Errata page&lt;/a&gt;, it turned out that because I had enabled desktop effects using &lt;span style="font-style: italic;"&gt;Compiz&lt;/span&gt;, I needed to also enable the &lt;span style="font-style: italic;"&gt;Compiz Video Playback&lt;/span&gt; plugin, using &lt;span style="font-style: italic;"&gt;ccsm&lt;/span&gt;. Once that was done, &lt;span style="font-style: italic;"&gt;MPlayer&lt;/span&gt; worked fine. However, other video players like &lt;span style="font-style: italic;"&gt;Kaffeine&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;Totem&lt;/span&gt; did not seem to work, but I didn't care much for those.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Wifi&lt;/span&gt;&lt;br /&gt;After trawling the Internet, I realized that I needed to reinstall the &lt;span style="font-style: italic;"&gt;iwlwifi-4965-ucode&lt;/span&gt; package, because the installer had removed some firmware files required by the built-in &lt;span style="font-style: italic;"&gt;Intel 4965AGN&lt;/span&gt; wireless adaptor. After that, wifi seemed to connect fine to my home wifi network that used WPA authentication.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;MandrivaUpdate over proxy&lt;/span&gt;&lt;br /&gt;At work, &lt;span style="font-style: italic;"&gt;MandrivaUpdate&lt;/span&gt; must be configured to go through an authenticated proxy before it could go out to grab updates from the Internet. Unfortunately, there seemed to be an inconsistency between how the proxy login and password were specified in the &lt;span style="font-style: italic;"&gt;urpmi&lt;/span&gt; configuration and &lt;span style="font-style: italic;"&gt;Network Settings&lt;/span&gt;. As a result, it was not possible to perform an update via &lt;span style="font-style: italic;"&gt;MandrivaUpdate&lt;/span&gt;. The workaround was just to do updates from the command line, using:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;urpmi --proxy server:port --proxy-user login:password ...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;MandrivaUpdate&lt;/span&gt; worked fine at home where it did not need to go through a proxy.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Things I did not quite like include:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Auto-partitioning&lt;/span&gt;&lt;br /&gt;The &lt;span style="font-style: italic;"&gt;Portege M800&lt;/span&gt; came with a 130GB harddisk. I chose to let the installer manage the partitioning this time and told it to copy the contents of the installation DVD onto disk. I had expected it to give several tens of GB for the "/" partition, a separate partition just to hold the DVD contents, and everything else for "/home". I was disappointed to see that the installer allocated a mere 8GB for "/" that also contained the DVD contents (~4GB). That left only 4GB for the entire OS plus any other programs I wanted to install. No where near enough because I  needed some large applications like an Oracle database. To fix this, I moved the DVD contents to a new directory under "/home", and made a symlink to it from the original location. That freed up 4GB that should hopefully be enough until my next upgrade to &lt;span style="font-style: italic;"&gt;Mandriva 2009.1&lt;/span&gt;. Next time, I'll choose custom partitioning.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Missing applications&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Missing altogether were KDE 3.x applications that had not been ported over to KDE 4.x, notably &lt;span style="font-style: italic;"&gt;K3B&lt;/span&gt;. Hopefully, this situation is remedied in the near future.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Now, the good bits...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Overall, I was impressed with this release. KDE 4 looked a lot better than KDE 3 in 2008.1. The desktop widgets were a pleasure to use, desktop effects were nicely integrated, performance was acceptable, and there was an abundance of applications from the PLF and contribs repositories. The"Start Application" menu had a new tabbed-style that I found more user-friendly on a laptop. Even the SD card reader worked properly.&lt;br /&gt;&lt;br /&gt;&lt;hr /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5156332309817509524-4870972087220981551?l=penguinman-techtalk.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://penguinman-techtalk.blogspot.com/feeds/4870972087220981551/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://penguinman-techtalk.blogspot.com/2008/12/mandriva-2009-on-toshiba-portege-m800.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5156332309817509524/posts/default/4870972087220981551'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5156332309817509524/posts/default/4870972087220981551'/><link rel='alternate' type='text/html' href='http://penguinman-techtalk.blogspot.com/2008/12/mandriva-2009-on-toshiba-portege-m800.html' title='Mandriva 2009 on Toshiba Portege M800'/><author><name>penguinman</name><uri>http://www.blogger.com/profile/03293300286288413519</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp1.blogger.com/_2oGca8ZQVtc/R4WUQFuS1jI/AAAAAAAAAAM/YRVdoPal21U/S220/XRayPenguinAvatar.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_2oGca8ZQVtc/SUJeWG6kWII/AAAAAAAAAD0/pv91nFSJWBE/s72-c/snapshot.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5156332309817509524.post-8890867794909464230</id><published>2008-11-26T21:29:00.000+11:00</published><updated>2008-11-27T18:40:58.546+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='seminar'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='sun developer day'/><title type='text'>Sun Developer Day 2008, Melbourne, Australia</title><content type='html'>&lt;span style="font-size:78%;"&gt;Note: Click on images to view in full size.&lt;/span&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://picasaweb.google.com.au/lh/photo/7YfbZj6qHEfs39g3AeuJNQ"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 165px; height: 123px;" src="http://lh3.ggpht.com/_2oGca8ZQVtc/SSz4Qra06uI/AAAAAAAAACI/cTxyTwI6nAo/s144/nokia126.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;I attended the Sun Developer Day in Melbourne, on November 26, 2008. It was hosted in the very fabulously furnished Grand Hyatt hotel. Upon arrival at the hall, I was greeted by Sun logos on brightly lit wall displays. I got there just in time for the Keynote speech. Below is a summary of the talks I attended, and what I thought about them.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;br /&gt;&lt;/h3&gt;&lt;h3&gt;&lt;br /&gt;&lt;/h3&gt;&lt;h3&gt;&lt;br /&gt;&lt;/h3&gt;&lt;h3&gt;&lt;br /&gt;&lt;/h3&gt;&lt;h3&gt;Keynote, by Reginald &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;Hutcherson&lt;/span&gt;&lt;/h3&gt;&lt;br /&gt;&lt;div style="margin: 0px 10px 0px 0px; display: block; float: left;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://picasaweb.google.com.au/lh/photo/lRjGcRqgv-XiiE_RHW8Z4w"&gt;&lt;img style="cursor: pointer; width: 165px; height: 123px;" src="http://lh4.ggpht.com/_2oGca8ZQVtc/SSz4Q2NUW8I/AAAAAAAAACQ/qZ5pGgTSO3o/s400/nokia127.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://picasaweb.google.com.au/lh/photo/JBm6t7zQH3KHskaJwrVY0g"&gt;&lt;img style="cursor: pointer; width: 165px; height: 123px;" src="http://lh4.ggpht.com/_2oGca8ZQVtc/SSz4RTVuAwI/AAAAAAAAACY/kmj5ahXUXI4/s288/nokia128.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Reginald is &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;undoubtably&lt;/span&gt; the best speaker of the day, in terms of presentation skills and the consistent pace of delivery. All the subsequent speakers seemed hurried. He stressed the importance of Open Source technologies for Sun, then briefly mentioned a host of technologies like &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;virtualization&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;MySQL&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;Glassfish&lt;/span&gt;&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;Rich Internet Applications&lt;/span&gt; (&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;RIA&lt;/span&gt;), &lt;span style="font-style: italic;"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;JavaFX&lt;/span&gt;&lt;/span&gt;, but the most interesting one for me was &lt;span style="font-style: italic;"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;zembly&lt;/span&gt;&lt;/span&gt;. Unfortunately he only had a single slide on &lt;span style="font-style: italic;"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;zembly&lt;/span&gt;&lt;/span&gt;, but I later gathered that its a Web site that allows users to create social applications that work on &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;Facebook&lt;/span&gt;, iPhone, etc. At this point in time, it is free to use while still in beta. Interesting... worth a second look once its released.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;br /&gt;&lt;/h3&gt;&lt;h3&gt;&lt;br /&gt;&lt;/h3&gt;&lt;h3&gt;&lt;br /&gt;&lt;/h3&gt;&lt;h3&gt;&lt;br /&gt;&lt;/h3&gt;&lt;h3&gt;&lt;br /&gt;&lt;/h3&gt;&lt;h3&gt;&lt;br /&gt;&lt;/h3&gt;&lt;h3&gt;&lt;br /&gt;&lt;/h3&gt;&lt;h3&gt;&lt;br /&gt;&lt;/h3&gt;&lt;h3&gt;&lt;br /&gt;&lt;/h3&gt;&lt;h3&gt;Demo shootout, by all three subsequent presenters&lt;/h3&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://picasaweb.google.com.au/lh/photo/yz9ffXleS5-8aHWzIHEA-g"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 144px; height: 108px;" src="http://lh4.ggpht.com/_2oGca8ZQVtc/SSz4Rjgt6WI/AAAAAAAAACg/kEF1rJD_KOo/s144/nokia129.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Two of the three demos were on &lt;span style="font-style: italic;"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;JavaFX&lt;/span&gt;&lt;/span&gt;. They were simple applications that mostly served as eye-candy to keep the audience entertained, as well as introducing &lt;span style="font-style: italic;"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_10"&gt;Netbeans&lt;/span&gt;&lt;/span&gt;. However, I've seen similar &lt;span style="font-style: italic;"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_11"&gt;JavaFX&lt;/span&gt;&lt;/span&gt; demos in previous Sun talks, so there wasn't much in them for me. I wished they showed different aspects of development, for example writing unit and integration tests for &lt;span style="font-style: italic;"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_12"&gt;JavaFX&lt;/span&gt;&lt;/span&gt; applications.&lt;br /&gt;&lt;br /&gt;The remaining demo was on &lt;span style="font-style: italic;"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_13"&gt;OpenSolaris&lt;/span&gt;&lt;/span&gt;. As expected, it started with GUI eye-candy effects like wobbly windows (nothing more than &lt;span style="font-style: italic;" class="blsp-spelling-error" id="SPELLING_ERROR_14"&gt;Ubuntu&lt;/span&gt;), followed by a sample &lt;span style="font-style: italic;"&gt;MySQL&lt;/span&gt; driven application. One thing that caught my interest was &lt;span style="font-style: italic;"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_15"&gt;VirtualBox&lt;/span&gt;&lt;/span&gt; that could seamlessly run applications from different hosted systems on the host desktop, as if they were running &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_16"&gt;natively&lt;/span&gt;, only with different window decorations.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_17"&gt;JavaNext&lt;/span&gt; - The future of Java SE, by &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_18"&gt;Chuk&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_19"&gt;Munn&lt;/span&gt; Lee&lt;/h3&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://picasaweb.google.com.au/lh/photo/P8KciWYbev-liXucWS9I1Q"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 144px; height: 108px;" src="http://lh3.ggpht.com/_2oGca8ZQVtc/SSz4SW2tQhI/AAAAAAAAACo/1UJfK_G6zek/s144/nokia131.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;For me, this was the highlight of the whole seminar. I was looking forward to hearing about upcoming features in Java, and this talk did not disappoint. New features that particularly interested me were:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Annotations on Java types (&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_20"&gt;JSR&lt;/span&gt; 308) to do stuff like enforcing invariants.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Modules to control access to Java packages. This involved adding a new &lt;span style="font-style: italic;"&gt;module&lt;/span&gt; keyword and a &lt;span style="font-style: italic;"&gt;module-info.java&lt;/span&gt; file to specify access rules. Modules would be packaged into JAM archives, that could also be pulled from &lt;span style="font-style: italic;"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_21"&gt;OSGI&lt;/span&gt;&lt;/span&gt; repositories.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Closures - woo &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_22"&gt;hoo&lt;/span&gt;!&lt;br /&gt;&lt;/li&gt;&lt;li&gt;New &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_23"&gt;APIs&lt;/span&gt; like Swing Application Framework (&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_24"&gt;JSR&lt;/span&gt; 296) and Beans Binding.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;There was mention of a new soft real-time garbage collector called &lt;span style="font-style: italic;"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_25"&gt;GarbageFirst&lt;/span&gt;&lt;/span&gt; for those having to do time sensitive applications, but this was not so relevant to me.&lt;br /&gt;&lt;br /&gt;I wish &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_26"&gt;Chuk&lt;/span&gt; told us what version of Java all these goodies would be coming in.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Connection the World with REST, by &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_27"&gt;Chuk&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_28"&gt;Munn&lt;/span&gt; Lee&lt;/h3&gt;&lt;br /&gt;The problem with this talk was too much introductory material on REST. I felt that REST is so widely known by most Web developers nowadays that basic knowledge such as verbs, resources, etc should have been assumed instead of wasting precious presentation time. Towards the end of the talk, &lt;span style="font-style: italic;"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_29"&gt;Jax&lt;/span&gt;-RS&lt;/span&gt; (&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_30"&gt;JSR&lt;/span&gt; 311) and the &lt;span style="font-style: italic;"&gt;Jersey&lt;/span&gt; implementation were mentioned. &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_31"&gt;Chuk&lt;/span&gt; briefly talked about how when &lt;span style="font-style: italic;"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_32"&gt;Jax&lt;/span&gt;-RS&lt;/span&gt; is integrated into Java &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_33"&gt;EE&lt;/span&gt;6, it will be able to work with/on &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_34"&gt;EE&lt;/span&gt; resources like &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_35"&gt;EJBs&lt;/span&gt;, Web Services, security, etc. &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_36"&gt;Chuk&lt;/span&gt; should have spent much more time on these new upcoming support for REST.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_37"&gt;JavaFX&lt;/span&gt; - &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_38"&gt;SDK&lt;/span&gt; and Compiler, by Angela &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_39"&gt;Caicedo&lt;/span&gt;&lt;/h3&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://picasaweb.google.com.au/lh/photo/g3_DQLL8rK_3dQI81XRnCQ"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 144px; height: 108px;" src="http://lh3.ggpht.com/_2oGca8ZQVtc/SSz6XXU9NtI/AAAAAAAAACw/cm6fUNWcwoA/s144/nokia132.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;This talk turned out to be more interesting and informative than I expected, probably due to me being new to &lt;span style="font-style: italic;"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_40"&gt;JavaFX&lt;/span&gt;&lt;/span&gt;. Angela introduced the newest syntax for variables, functions, binding, effects, animation and events. Pages and pages of code snippets... just the way I liked them. In addition, the following were discussed:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Architecture of the &lt;span style="font-style: italic;"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_41"&gt;JavaFX&lt;/span&gt;&lt;/span&gt; framework.&lt;/li&gt;&lt;li&gt;Pull parser that supported &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_42"&gt;JSON&lt;/span&gt; and XML.&lt;/li&gt;&lt;li&gt;Ability to access &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_43"&gt;RESTful&lt;/span&gt; resources.&lt;/li&gt;&lt;li&gt;New browser &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_44"&gt;plugin&lt;/span&gt; architecture.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h3&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_45"&gt;SOA&lt;/span&gt; with &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_46"&gt;OpenESB&lt;/span&gt; and Java CAPS 6.0, by &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_47"&gt;Chuk&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_48"&gt;Munn&lt;/span&gt; Lee&lt;/h3&gt;There was one word to describe developing for &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_49"&gt;SOA&lt;/span&gt; :- &lt;span style="font-weight: bold;"&gt;tedious&lt;/span&gt;, and this demo-talk did little to persuade me otherwise. A demo loan approval application was implemented as a document-centric Web Service, using &lt;span style="font-style: italic;"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_50"&gt;OpenESB&lt;/span&gt;&lt;/span&gt; running on &lt;span style="font-style: italic;"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_51"&gt;Glassfish&lt;/span&gt;&lt;/span&gt;. Of course, &lt;span style="font-style: italic;"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_52"&gt;Netbeans&lt;/span&gt; 6.5&lt;/span&gt; was the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_53"&gt;IDE&lt;/span&gt;. Starting from some existing &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_54"&gt;XSD&lt;/span&gt; data &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_55"&gt;schemas&lt;/span&gt;, the basic steps were to create a &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_56"&gt;WSDL&lt;/span&gt;, define a &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_57"&gt;BPEL&lt;/span&gt;, bind with a Stateless Session &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_58"&gt;EJB&lt;/span&gt;, run some integration tests against the service, then finally generating a Java client. The presenter had to go back and forth through various &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_59"&gt;IDE&lt;/span&gt; panes and dialogs, to define &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_60"&gt;WSDL&lt;/span&gt; parameters, access various URI and port settings, etc, ... I really hated these sort of complex manual steps.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;MySQL - A Developer Perspective, by Peter &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_61"&gt;Karlsson&lt;/span&gt;&lt;/h3&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://picasaweb.google.com.au/lh/photo/h7PMxuSgF-Vd0vSzfK3cOw"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 144px; height: 108px;" src="http://lh5.ggpht.com/_2oGca8ZQVtc/SSz6YwyxrpI/AAAAAAAAADI/AqQEKLUGukY/s144/nokia136.jpg" alt="" border="0" /&gt;&lt;/a&gt;This was an interesting talk about a database I've used a lot. Peter compared several storage engines in &lt;span style="font-style: italic;"&gt;MySQL 5.1&lt;/span&gt; and usage scenarios for them. This was followed by a discussion on how to optimize database queries, which were pretty basic stuff not specific to &lt;span style="font-style: italic;"&gt;MySQL&lt;/span&gt;. There was nothing much that was new here, nevertheless a useful reminder of the things to consider when designing a database schema.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;br /&gt;&lt;/h3&gt;&lt;h3&gt;&lt;br /&gt;&lt;/h3&gt;&lt;h3&gt;&lt;br /&gt;&lt;/h3&gt;&lt;h3&gt;&lt;br /&gt;&lt;/h3&gt;&lt;h3&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_62"&gt;Netbeans&lt;/span&gt; 6.5, by Angela &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_63"&gt;Caicedo&lt;/span&gt;&lt;/h3&gt;I guessed this talk was meant to show off as many features of &lt;span style="font-style: italic;"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_64"&gt;Netbeans&lt;/span&gt; 6.5&lt;/span&gt; as possible in the time available. Unfortunately, there was so much in this &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_65"&gt;IDE&lt;/span&gt; to fit into a single talk. Quite a lot of time was wasted showing off standard features like refactoring, perhaps the speaker should have concentrated on features that were not found in &lt;span style="font-style: italic;"&gt;Eclipse&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;The compile-on-save and live-update-refresh features seemed handy. I wished there was some mention of &lt;span style="font-style: italic;"&gt;Ruby/Rails&lt;/span&gt; support and Unit Testing of new technologies like &lt;span style="font-style: italic;"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_66"&gt;JavaFX&lt;/span&gt;&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Skipped talks&lt;/h3&gt;I skipped the last couple of talks, on &lt;span style="font-style: italic;"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_67"&gt;DTrace&lt;/span&gt;&lt;/span&gt; and &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_68"&gt;virtualization&lt;/span&gt;, as they were both &lt;span style="font-style: italic;"&gt;Solaris&lt;/span&gt; specific and I don't use &lt;span style="font-style: italic;"&gt;Solaris&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;LUNCH&lt;/h3&gt;&lt;div style="margin: 0px 10px 0px 0px; display: block; float: left;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://picasaweb.google.com.au/lh/photo/BsshhnWy8Aec89FEWTjqMA"&gt;&lt;img style="cursor: pointer; width: 165px; height: 123px;" src="http://lh5.ggpht.com/_2oGca8ZQVtc/SSz6X-pVB7I/AAAAAAAAAC4/a9gq7i2V0hM/s144/nokia133.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://picasaweb.google.com.au/lh/photo/Z937xXN5fBYd7EwhusQHPw"&gt;&lt;img style="cursor: pointer; width: 165px; height: 123px;" src="http://lh6.ggpht.com/_2oGca8ZQVtc/SSz6YvB7bMI/AAAAAAAAADA/K4DcToLVImY/s144/nokia135-001.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;/div&gt;Lunch was surprisingly good considering this was a free seminar. There were abundant sandwiches, desserts, salads, chicken/beef satay skewers, and pizzas. I especially enjoyed the salmon pizza.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:78%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:78%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;All photos were taken using my &lt;span style="font-style: italic;"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_69"&gt;Nokia&lt;/span&gt; N95-8GB&lt;/span&gt;.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5156332309817509524-8890867794909464230?l=penguinman-techtalk.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://penguinman-techtalk.blogspot.com/feeds/8890867794909464230/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://penguinman-techtalk.blogspot.com/2008/11/sun-developer-day-2008-melbourne.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5156332309817509524/posts/default/8890867794909464230'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5156332309817509524/posts/default/8890867794909464230'/><link rel='alternate' type='text/html' href='http://penguinman-techtalk.blogspot.com/2008/11/sun-developer-day-2008-melbourne.html' title='Sun Developer Day 2008, Melbourne, Australia'/><author><name>penguinman</name><uri>http://www.blogger.com/profile/03293300286288413519</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp1.blogger.com/_2oGca8ZQVtc/R4WUQFuS1jI/AAAAAAAAAAM/YRVdoPal21U/S220/XRayPenguinAvatar.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_2oGca8ZQVtc/SSz4Qra06uI/AAAAAAAAACI/cTxyTwI6nAo/s72-c/nokia126.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5156332309817509524.post-2320042710262235208</id><published>2007-06-20T17:16:00.000+10:00</published><updated>2008-11-26T21:09:59.132+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sansa e250'/><category scheme='http://www.blogger.com/atom/ns#' term='mp3 player'/><category scheme='http://www.blogger.com/atom/ns#' term='video encoding'/><title type='text'>Images and videos for Sansa E250</title><content type='html'>After several days of researching, I finally found a way of encoding photos as 16-bpp bitmap images  for my &lt;span style="font-style: italic;"&gt;Sandisk Sansa E250&lt;/span&gt; Media player on my &lt;span style="font-style: italic;"&gt;Mandriva Linux 2008.1&lt;/span&gt; desktop.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Gimp&lt;/span&gt; 2.4 (I’m using 2.4.5) supports saving of 16 bpp bitmap which works on the E250. First crop and scale image to &lt;span style="font-weight: bold;"&gt;176×224&lt;/span&gt; pixels. Then &lt;span style="font-weight: bold;"&gt;flip the image vertically&lt;/span&gt;, so that top becomes bottom and vice versa.  Finally, save as bitmap. A dialog box will appear that provides Advanced Options. Expand it and select “16 bits R5 G6 B5″.&lt;br /&gt;&lt;br /&gt;I can now view my photos using my media player.  :)&lt;br /&gt;Grant, from &lt;a href="http://www.visi.com/%7Egrante/sansa"&gt;http://www.visi.com/~grante/sansa&lt;/a&gt;, provided a script to encode videos for the E250, but only in black-and-white. I modified it to encode audio to standard pcm codec, instead of Grant’s specially patched pcms. Then I run it though ffmpeg to convert the audio to big-endian format.&lt;br /&gt;&lt;br /&gt;Here’s how my script looks like (it writes to a temporary file) :&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;mencoder -ofps 15 -vf rotate=1,scale=160:208 -ffourcc mjpb -ovc lavc -lavcopts vcodec=mjpeg:vbitrate=150:vhq:gray -oac pcm -srate 11025 -of lavf ${1} -o /tmp/video.mov&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;ffmpeg -i /tmp/video.mov -vcodec copy -acodec pcm_s16be ${2}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;rm -f /tmp/video.mov&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Note that older versions of mencoder, prior to 2008 I think, required the following option.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;-lavfopts i_certify_that_my_video_stream_does_not_use_b_frames&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;in order to produce a video that works on the E250. This is no longer the case with the current version.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5156332309817509524-2320042710262235208?l=penguinman-techtalk.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://penguinman-techtalk.blogspot.com/feeds/2320042710262235208/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://penguinman-techtalk.blogspot.com/2007/06/images-and-videos-for-sansa-e250.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5156332309817509524/posts/default/2320042710262235208'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5156332309817509524/posts/default/2320042710262235208'/><link rel='alternate' type='text/html' href='http://penguinman-techtalk.blogspot.com/2007/06/images-and-videos-for-sansa-e250.html' title='Images and videos for Sansa E250'/><author><name>penguinman</name><uri>http://www.blogger.com/profile/03293300286288413519</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp1.blogger.com/_2oGca8ZQVtc/R4WUQFuS1jI/AAAAAAAAAAM/YRVdoPal21U/S220/XRayPenguinAvatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5156332309817509524.post-7484730276003843179</id><published>2007-06-12T18:46:00.000+10:00</published><updated>2008-11-26T21:10:56.952+11:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sansa e250'/><category scheme='http://www.blogger.com/atom/ns#' term='mp3 player'/><title type='text'>SanDisk E250 + Linux</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://penguinman.blogs.friendster.com/photos/uncategorized/sandiske250.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 200px; height: 200px;" src="http://penguinman.blogs.friendster.com/photos/uncategorized/sandiske250.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;I purchased a &lt;em&gt;SanDisk E250&lt;/em&gt; Media Player with 2GB storage, mainly to play MP3s, but it also views images and plays video clips. It was on sale in &lt;em&gt;JB Hi Fi&lt;/em&gt;, so I paid A$168 for it. I’m using it with my &lt;em&gt;Mandriva Linux&lt;/em&gt;&lt;/span&gt; desktop PC at home. &lt;p&gt;&lt;span style="font-size:100%;"&gt;I’ve only played with it a few hours. Despite good Linux connectivity support, there are some annoying shortcomings that dragged this product down.&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style="font-size:100%;"&gt;Here are the pros and cons (in my opinion):&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style="font-size:100%;"&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt; &lt;ol&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;Very easy USB connectivity to my Linux PC. Just set it to use Mass Storage mode and it automatically mounted when plugged into the PC. This is a VERY BIG PLUS for me, since Linux is all I use.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;Clear screen, good quality sound.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;Intuitive and easy-to-get-started interface.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;Supports Chinese title text (but only after changing the language to Chinese).&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;&lt;span style="font-size:100%;"&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt; &lt;ol&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;Does not seem to be able to group songs into directories. All songs from all sub-directories are listed. There is however a play-list that one can add songs to, but only one play-list. It does grouping based on ID3 v2 tags, so I work around this limitation by setting the Album tag using a little program called &lt;em&gt;id3v2&lt;/em&gt;. Its still a hassle to have to manually set this tag for all the MP3s that I upload to the player.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;Very limit support for image (&lt;em&gt; 16 bpp BMP&lt;/em&gt;) and video (&lt;em&gt;MJPEG Quicktime&lt;/em&gt;) formats. The player comes with a Windoze-only media converter software that’s useless to me of course. &lt;em&gt;Gimp&lt;/em&gt; can now be used to save images as 16 bpp bitmap. Video encoding is &lt;span&gt;also &lt;/span&gt;very tricky as most other blogs on the Web are also complaining of the difficulty of encoding to the very peculiar color format. Hopefully someone out there knows the required &lt;em&gt;mencoder&lt;/em&gt; options for this. I have no idea why SanDisk chose such weird formats for an otherwise very capable player. Very frustrating!&lt;/span&gt; &lt;/li&gt;&lt;li&gt;&lt;span style="font-size:100%;"&gt;Built-in batteries that can only be charged when plugged into a computer’s USB port, and the computer must be left on. There is an option to use a AC adaptor, but that’s an extra accessory.&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;&lt;span style="font-size:100%;"&gt;Overall, I can only give it a barely passing mark.&lt;/span&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5156332309817509524-7484730276003843179?l=penguinman-techtalk.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://penguinman-techtalk.blogspot.com/feeds/7484730276003843179/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://penguinman-techtalk.blogspot.com/2008/11/sandisk-e250-linux.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5156332309817509524/posts/default/7484730276003843179'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5156332309817509524/posts/default/7484730276003843179'/><link rel='alternate' type='text/html' href='http://penguinman-techtalk.blogspot.com/2008/11/sandisk-e250-linux.html' title='SanDisk E250 + Linux'/><author><name>penguinman</name><uri>http://www.blogger.com/profile/03293300286288413519</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://bp1.blogger.com/_2oGca8ZQVtc/R4WUQFuS1jI/AAAAAAAAAAM/YRVdoPal21U/S220/XRayPenguinAvatar.jpg'/></author><thr:total>0</thr:total></entry></feed>
