<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Lumenovis</title>
	<atom:link href="http://lumenovis.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://lumenovis.com</link>
	<description>Technology Consulting and Software Development</description>
	<lastBuildDate>Sun, 08 Aug 2010 13:33:37 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>C + C = A</title>
		<link>http://lumenovis.com/2010/07/09/c-c-a/</link>
		<comments>http://lumenovis.com/2010/07/09/c-c-a/#comments</comments>
		<pubDate>Fri, 09 Jul 2010 22:22:33 +0000</pubDate>
		<dc:creator>Dan</dc:creator>
				<category><![CDATA[Software Development]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[talent]]></category>

		<guid isPermaLink="false">http://lumenovis.com/?p=177</guid>
		<description><![CDATA[It&#8217;s said that one definition of insanity is doing the same thing over and over but expecting different results.  By that definition most of us are probably a little insane, and most of the businesses I&#8217;ve worked with even more so.  I&#8217;m going to spend some time over the next few postings discussing some of [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s said that one definition of insanity is doing the same thing over and over but expecting different results.  By that definition most of us are probably a little insane, and most of the businesses I&#8217;ve worked with even more so.  I&#8217;m going to spend some time over the next few postings discussing some of these tried and true, repeatable methods for underperforming or failing.  The first installment:  C + C = A.</p>
<p>If you&#8217;ve been in the technology field for any length of time, you witnessed some variation of this logic:</p>
<ol>
<li>The company has a budget X for a certain project/product.</li>
<li>We need as many people as we can get for that budget.</li>
<li>Let&#8217;s avoid top talent and instead target the market average (or below) to get as many people as possible.</li>
<li>Let&#8217;s apply the latest hot methodology to produce a great product (a topic for another day).</li>
</ol>
<p>In other words, I&#8217;m going to create a team of C players but expect A results.  C + C = A.</p>
<p>The major breakdown here is, of course, #2: the assumption that quantity begets productivity.  While that is true in some cases (you can&#8217;t build a massive, multi-million-lines-of-code enterprise system in a reasonable timeframe with 2-3 sharp developers), it is not true when you measure across quality levels.  Ten C-players will probably not out-produce 5 A-players.  In fact, they might not even outproduce 1 A-player.  If the problem is complex, the C-players may never deliver an acceptable solution.</p>
<p>I&#8217;ve seen many variations of these cases play out in the real world.  I&#8217;ve seen a large development team shed 1/3 of it&#8217;s (bottom ranking) staff and improve productivity by 50% or more.  I&#8217;ve seen a small group of A-players produce an order of magnitude (yes, 10X) more features in a given time period than a larger group of C-players.  But most of all, I&#8217;ve seen teams of C players produce lots and lots of C results, followed by inevitable surprise and confusion at the management level.</p>
<p>So if it&#8217;s clear that, in many or most cases, net productivity improves when you go up-talent, why don&#8217;t companies do so?  In my experience, the number one reason is concerns about cost (actual or perceived).  Paying 20-40% more for an A player (vs. a C player) seems prohibitive on a person-by-person basis, but once you look at the ratio of productivity to cost at the team level, it quickly becomes apparent that going up-talent is probably a net cost savings.  If I had a budget of X, I&#8217;d much rather hire 6 A players than 10 C players, knowing full well that I&#8217;ll get a 2-3X productivity boost even with fewer bodies.</p>
<p>But management (especially CFOs and financial types) generally can&#8217;t get past the cost of the individual resources.  Large companies are often driven by the CFOs, who are by and large focussed on raising the top line and reducing the bottom line on a quarterly or annual basis; in their quest to squeeze out all costs, they get a little gassy when they see high-dollar individuals on the payroll.  In short they see top-performers as an expense item, and not as an investment in future success.  Great for the short run; not so good if you want to be competitive 3-5 years from now.</p>
<p>A more reasonable excuse is finding that talent- there are not many A players on the market, and the companies that have them keep them.  But it&#8217;s not impossible to move up-talent over time.  Companies that are brutally honest in their evaluations and ones that refuse to keep low-talent can move up-talent over time.  I believe it&#8217;s possible to bump up a full grade level within a year or two with some firm commitment.  But again, this is tough.  Companies and made of people, and people live by relationships, and relationships make it sometimes hard to do what is best for the team.  Likewise companies (and their management) like to think they&#8217;ve done a great job building a great team (like the old adage about 70% of people thinking of themselves as above average)&#8230; deep down many of these managers are resistant to going up-talent.</p>
<p>Another reason is &#8220;thrashing&#8221;, which results when C players produce a faulty, leaky system, and then massive amounts of manpower have to be thrown at the problems to keep them at bay.  In this case you are caught between a rock and hard place- you can&#8217;t shed too many bodies since you simply need numbers to spread them out over all the problems.  Once you&#8217;re at this point, good luck.  I&#8217;m sure you&#8217;ll spend many painful sleepless nights wishing you (or your predecessor) had invested in A players and avoided the problems altogether.</p>
<p>I&#8217;m running out of time for this entry, but suffice it to say that there are more reasons for the perpetuation of this insanity, and I see no evidence that it will stop (in aggregate).  That said, there are plenty of exceptions to the rule- teams that have invested in A-talent and are reaping the benefit; teams that are working hard to move up-talent; etc.  Kudos to these teams.  And if you&#8217;re on the wrong side of the insanity, just know that it&#8217;s never too late start moving up-talent.</p>
<p>By the way, there is a variation of this myth known as outsourcing, but we&#8217;ll hit that another day.</p>
]]></content:encoded>
			<wfw:commentRss>http://lumenovis.com/2010/07/09/c-c-a/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>To be right or to be effective?</title>
		<link>http://lumenovis.com/2010/06/23/be-right-or-be-effective/</link>
		<comments>http://lumenovis.com/2010/06/23/be-right-or-be-effective/#comments</comments>
		<pubDate>Wed, 23 Jun 2010 23:02:43 +0000</pubDate>
		<dc:creator>Dan</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[leadership]]></category>
		<category><![CDATA[management]]></category>

		<guid isPermaLink="false">http://lumenovis.com/?p=185</guid>
		<description><![CDATA[Thoughts on how to go from being "right" to being "effective"]]></description>
			<content:encoded><![CDATA[<p>A few years ago I was having lunch with William (not his real name).  William was a former colleague of mine at a recent startup.  William was one of the hardest chargers I&#8217;ve ever worked with; as a key leader in the quality assurance and configuration management departments, he was always available, 24&#215;7, and ran a very tight ship.  He was also a former military special forces warrior and was generally unconcerned about collateral damage as long as the mission was accomplished- in other words, he caused a lot of hard feelings.</p>
<p>William asked me to lunch to catch up and to discuss some challenges he was having in a new position; not surprisingly, his style was creating some friction.  He was perplexed because, for the most part, he was &#8220;in the right&#8221;.  The new organization needed some serious discipline and procedural house cleaning, and William was doing everything in his power to make the changes as quickly as possible.</p>
<p>William was caught in the classic trap- he was &#8220;right&#8221;, but he wasn&#8217;t being &#8220;effective.&#8221;  I see this all the time, and I&#8217;m guilty more often than I&#8217;d like to admit.  When you know you&#8217;re right, it is very seductive to take what appears to be the shortest route, which is ofter to simply announce that &#8220;this is the way it will be, because I&#8217;m right&#8221; (or some variation).</p>
<p>But the truth is that being right is not enough if you actually want to make a difference.  Sun Tzu said it well: &#8220;In war, then, <em>let your</em> great object be <em>victory</em>, not lengthy campaigns.&#8221;  You can be &#8220;right&#8221; over and over and never get out of the campaign.  Being effective requires you to expand your definition of &#8220;victory.&#8221;  Your &#8220;great object&#8221; (i.e. goal) is to bring about some change, not to achieve a state of moral righteousness.</p>
<p>So how do you go from being &#8220;right&#8221; to being &#8220;effective&#8221;.  That&#8217;s more art than science, but here&#8217;s a few guidelines I try to keep in mind:</p>
<p>-  When possible, take some time socializing the idea.  Change is scary to many people, so allow for some time.  Once a critical mass of the group believes its a good idea, then it&#8217;s a done deal.</p>
<p>-  Get buy-in from the leadership (peers or superiors).</p>
<p>-  Create a sense of ownership; make it everyone&#8217;s idea, not just yours.</p>
<p>-  Listen.  Let people voice their objections or concerns.  Address them with respect.  Use them to beter the idea.</p>
<p>-  Let others fight the battle.  If you can convince a few &#8220;thought leaders&#8221; of your idea, let them run with it.  Don&#8217;t hesitate to give them credit (or even let them take credit).</p>
<p>-  Stay focussed on the real victory conditions.  It&#8217;s easy to get bogged down in tactical conflicts, but if you stay focussed on the end-game, you&#8217;ll be in a great position to compromise or even back down in areas that are not critical to getting the idea done.  &#8221;Lose the battle but win the war&#8221; is a great tool to have in the toolbox.</p>
<p>-  Be willing to compromise and be patient.  If you can get 50% of your idea implemented without much fuss today vs. 100% with major push-back, I&#8217;d take the 50% and then go after the remainder in the next round.</p>
<p>-  Use Guerilla tactics (carefully).  It&#8217;s sometimes helpful to throw an idea on the table that is so unpleasant that your original idea looks positively great by comparison.  This works best if someone else floats the idea.</p>
<p>-  Last, but perhaps most important, lead by example.  If you can show personally or within your organization that your idea not only works but gives you and your team a competitive advantage, others will be highly motivated to get on board.</p>
]]></content:encoded>
			<wfw:commentRss>http://lumenovis.com/2010/06/23/be-right-or-be-effective/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Grails ROCKS!</title>
		<link>http://lumenovis.com/2010/03/24/grails-rocks/</link>
		<comments>http://lumenovis.com/2010/03/24/grails-rocks/#comments</comments>
		<pubDate>Thu, 25 Mar 2010 04:38:20 +0000</pubDate>
		<dc:creator>Dan</dc:creator>
				<category><![CDATA[Software Development]]></category>
		<category><![CDATA[agile]]></category>
		<category><![CDATA[Grails]]></category>
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://lumenovis.com/?p=170</guid>
		<description><![CDATA[Grails development.]]></description>
			<content:encoded><![CDATA[<p>So I&#8217;ve been pretty heads down for the last year cranking out a number of enterprise Java, service provider, and iPhone projects.  It&#8217;s been a hugely productive period and I&#8217;ve both taught and learned a great deal.  One of the highlights, though, has to be diving into the Grails web application development framework.  If you&#8217;re not familiar with Grails, it&#8217;s a &#8220;convention over configuration&#8221; framework (much like Ruby on Rails) that sits on top of Spring and Hibernate and leverages Groovy to make development faster and easier.  It was a bit of a steep learning curve (probably because I refused to read any of the great books out there (e.g. Grails in Action) and instead tried to learn on the go), but now that I&#8217;m up to speed I have to say that it&#8217;s made web development fun again.  Gone are the hours and hours futzing with build configurations and XML files.  Gone are the days of writing boilerplate code to transfer data from the brower to the database and back.  With Grails, most of the tedious stuff is done &#8220;automagically&#8221; and you can focus on cranking out your app.  My unscientific estimate is that I&#8217;m producing features 3-5x faster with Grails than I can with Struts 2 or Spring MVC.  Seriously- it&#8217;s that good.</p>
<p>Here&#8217;s an example.  I&#8217;m finishing on an app for a nationwide company that decided a couple of weeks before the portal was to go live that it needed to support co-branding for all of their clients- basically, display a custom logo depending on who was logged in.  The right answer should have been &#8220;No!&#8221; since we were short on time and had limited resources available, but I had a hunch that Grails would make it easy enough to take on despite the risk.  So I branched the code (just in case), started a timer (literally) and dove into it.  I developed a &#8220;Brand&#8221; table that would store name, styles, and logos.  I developed full featured CRUD pages for admins to add, change, and delete brands.  I added the Brand section to the Admin section of the portal.  I modified the portal pages to show the brand logos when available.  And I developed a servlet (&#8220;controller&#8221; in Grails) to serve up images out of the database.  Grand total:  35 minutes and maybe 50 lines of handwritten code.  (To be fair, I should also add another 30-60 minutes for automated test development and testing.)  My guess is that this would have been a couple of days in any other framework.</p>
<p>If you&#8217;re a Java web developer do yourself a favor and have a look.  I think you won&#8217;t be disappointed.</p>
]]></content:encoded>
			<wfw:commentRss>http://lumenovis.com/2010/03/24/grails-rocks/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Text Message Marketing App</title>
		<link>http://lumenovis.com/2009/05/28/text-message-marketing-app/</link>
		<comments>http://lumenovis.com/2009/05/28/text-message-marketing-app/#comments</comments>
		<pubDate>Thu, 28 May 2009 22:12:33 +0000</pubDate>
		<dc:creator>Dan</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://lumenovis.com/?p=153</guid>
		<description><![CDATA[I recent worked with a friend on an app for his text messaging marketing product called Goomzee.  The first version of Goomzee mobile allows real estate professionals to track all of their listings, campaigns and leads from their phone, enabling immediate and effective response to inquiries.   I developed the UI and stubbed out the [...]]]></description>
			<content:encoded><![CDATA[<p>I recent worked with a friend on an app for his text messaging marketing product called Goomzee.  The first version of Goomzee mobile allows real estate professionals to track all of their listings, campaigns and leads from their phone, enabling immediate and effective response to inquiries.   I developed the UI and stubbed out the data layer for his initial demos and product trials; the app is currently being wired up to his web services.  Screenshots below.</p>
<p><a href="http://lumenovis.com/wp-content/uploads/2009/06/screenshot-20090624-143223.png"><img class="alignnone size-medium wp-image-154" title="screenshot-20090624-143223" src="http://lumenovis.com/wp-content/uploads/2009/06/screenshot-20090624-143223-200x300.png" alt="" width="200" height="300" /></a> <a href="http://lumenovis.com/wp-content/uploads/2009/06/screenshot-20090624-143228.png"><img class="alignnone size-medium wp-image-155" title="screenshot-20090624-143228" src="http://lumenovis.com/wp-content/uploads/2009/06/screenshot-20090624-143228-200x300.png" alt="" width="200" height="300" /></a> <a href="http://lumenovis.com/wp-content/uploads/2009/06/screenshot-20090624-143243.png"><img class="alignnone size-medium wp-image-156" title="screenshot-20090624-143243" src="http://lumenovis.com/wp-content/uploads/2009/06/screenshot-20090624-143243-200x300.png" alt="" width="200" height="300" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://lumenovis.com/2009/05/28/text-message-marketing-app/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>First Responder Application</title>
		<link>http://lumenovis.com/2009/05/14/first-responder-application/</link>
		<comments>http://lumenovis.com/2009/05/14/first-responder-application/#comments</comments>
		<pubDate>Thu, 14 May 2009 20:43:07 +0000</pubDate>
		<dc:creator>Dan</dc:creator>
				<category><![CDATA[iPhone]]></category>
		<category><![CDATA[first responder]]></category>

		<guid isPermaLink="false">http://lumenovis.com/?p=147</guid>
		<description><![CDATA[I recently worked with on an interesting application for first responders.  This app allows volunteer firemen (for example) to announce their location and availability with the click of a button upon receipt of an alarm.  Their peers and leaders can then see updated location and response information in near realtime, allowing for more effective decision [...]]]></description>
			<content:encoded><![CDATA[<p>I recently worked with on an interesting application for first responders.  This app allows volunteer firemen (for example) to announce their location and availability with the click of a button upon receipt of an alarm.  Their peers and leaders can then see updated location and response information in near realtime, allowing for more effective decision making.  The app makes heavy use of REST polling and messaging plus mapping via Google Maps and has hooks for realtime communications.</p>
<p><a href="http://lumenovis.com/wp-content/uploads/2009/06/screenshot-20090512-082048.png"><img class="alignnone size-medium wp-image-148" title="screenshot-20090512-082048" src="http://lumenovis.com/wp-content/uploads/2009/06/screenshot-20090512-082048-200x300.png" alt="" width="200" height="300" /></a> <a href="http://lumenovis.com/wp-content/uploads/2009/06/screenshot-20090512-082107.png"><img class="alignnone size-medium wp-image-149" title="screenshot-20090512-082107" src="http://lumenovis.com/wp-content/uploads/2009/06/screenshot-20090512-082107-200x300.png" alt="" width="200" height="300" /></a> <a href="http://lumenovis.com/wp-content/uploads/2009/06/screenshot-20090512-082130.png"><img class="alignnone size-medium wp-image-150" title="screenshot-20090512-082130" src="http://lumenovis.com/wp-content/uploads/2009/06/screenshot-20090512-082130-200x300.png" alt="" width="200" height="300" /></a> <a href="http://lumenovis.com/wp-content/uploads/2009/06/screenshot-20090512-082137.png"><img class="alignnone size-medium wp-image-151" title="screenshot-20090512-082137" src="http://lumenovis.com/wp-content/uploads/2009/06/screenshot-20090512-082137-200x300.png" alt="" width="200" height="300" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://lumenovis.com/2009/05/14/first-responder-application/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>KiddyBase 1.0</title>
		<link>http://lumenovis.com/2009/03/23/kiddybase-10/</link>
		<comments>http://lumenovis.com/2009/03/23/kiddybase-10/#comments</comments>
		<pubDate>Mon, 23 Mar 2009 17:40:34 +0000</pubDate>
		<dc:creator>Dan</dc:creator>
				<category><![CDATA[iPhone]]></category>
		<category><![CDATA[kiddybase]]></category>

		<guid isPermaLink="false">http://lumenovis.com/?p=136</guid>
		<description><![CDATA[I just wrapped up version 1 of KiddyBase, the electronic baby book for iPhone. The idea came to me after watching my wife agonize to remember what the kids had said or done over the past week/month. I looked around and found a few height/weight trackers, but no comprehensive journal to track the baby&#8217;s milestones. [...]]]></description>
			<content:encoded><![CDATA[<p>I just wrapped up version 1 of KiddyBase, the electronic baby book for iPhone.  The idea came to me after watching my wife agonize to remember what the kids had said or done over the past week/month.  I looked around and found a few height/weight trackers, but no comprehensive journal to track the baby&#8217;s milestones.  Thus was KiddyBase born.</p>
<p>You can read more about the app in the product section.  Here are some additional screenshots:<br />
<a href="http://lumenovis.com/wp-content/uploads/2009/03/screenshot-20090318-223550.jpg"><img class="alignnone size-medium wp-image-127" title="screenshot-20090318-223550" src="http://lumenovis.com/wp-content/uploads/2009/03/screenshot-20090318-223550-200x300.jpg" alt="" width="200" height="300" /></a> <img class="alignnone size-medium wp-image-143" title="screenshot-20090624-125858" src="http://lumenovis.com/wp-content/uploads/2009/06/screenshot-20090624-125858-200x300.png" alt="" width="200" height="300" /> <a href="http://lumenovis.com/wp-content/uploads/2009/03/screenshot-20090318-224140.jpg"><img class="alignnone size-medium wp-image-138" title="screenshot-20090318-224140" src="http://lumenovis.com/wp-content/uploads/2009/03/screenshot-20090318-224140-200x300.jpg" alt="" width="200" height="300" /></a> <a href="http://lumenovis.com/wp-content/uploads/2009/03/screenshot-20090318-224211.jpg"><img class="alignnone size-medium wp-image-139" title="screenshot-20090318-224211" src="http://lumenovis.com/wp-content/uploads/2009/03/screenshot-20090318-224211-200x300.jpg" alt="" width="200" height="300" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://lumenovis.com/2009/03/23/kiddybase-10/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>iPhone Conversion Application</title>
		<link>http://lumenovis.com/2009/02/25/iphone-conversion-application/</link>
		<comments>http://lumenovis.com/2009/02/25/iphone-conversion-application/#comments</comments>
		<pubDate>Wed, 25 Feb 2009 18:14:47 +0000</pubDate>
		<dc:creator>Dan</dc:creator>
				<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Objective C]]></category>
		<category><![CDATA[XML]]></category>

		<guid isPermaLink="false">http://lumenovis.com/?p=88</guid>
		<description><![CDATA[I was recently contracted to develop a conversion application for the iPhone called &#8220;All in One Converter&#8221;, with a focus on business users. This was a fun project in that: I chose to develop a generalized XML processing engine that would allow the creation and deployment of new conversion sets on the fly. we developed [...]]]></description>
			<content:encoded><![CDATA[<p>I was recently contracted to develop a conversion application for the iPhone called &#8220;All in One Converter&#8221;, with a focus on business users.  This was a fun project in that:</p>
<ol>
<li> I chose to develop a generalized XML processing engine that would allow the creation and deployment of new conversion sets on the fly.</li>
<li> we developed a proxy server to feed currency updates</li>
<li> I developed a full calculator stack that runs inline with the converter</li>
<li> I created a flexible &#8220;favorites&#8221; or bookmarking mechanism</li>
<li> we &#8220;invented&#8221; the Zone Scheduler, which helps schedule meeting across time zones</li>
</ol>
<p>Attached are some screenshots.  Should be in the iTunes store shortly.</p>
<div id="attachment_91" class="wp-caption alignnone" style="width: 210px"><a href="http://lumenovis.com/wp-content/uploads/2009/02/screenshot-20090225-112027.png"><img class="size-medium wp-image-91" title="screenshot-20090225-112027" src="http://lumenovis.com/wp-content/uploads/2009/02/screenshot-20090225-112027-200x300.png" alt="Conversion View" width="200" height="300" /></a><p class="wp-caption-text">Conversion View</p></div>
<div id="attachment_92" class="wp-caption alignnone" style="width: 210px"><a href="http://lumenovis.com/wp-content/uploads/2009/02/screenshot-20090225-112033.png"><img class="size-medium wp-image-92" title="screenshot-20090225-112033" src="http://lumenovis.com/wp-content/uploads/2009/02/screenshot-20090225-112033-200x300.png" alt="Calculator View" width="200" height="300" /></a><p class="wp-caption-text">Calculator View</p></div>
<div id="attachment_93" class="wp-caption alignnone" style="width: 210px"><a href="http://lumenovis.com/wp-content/uploads/2009/02/screenshot-20090225-112143.png"><img class="size-medium wp-image-93" title="screenshot-20090225-112143" src="http://lumenovis.com/wp-content/uploads/2009/02/screenshot-20090225-112143-200x300.png" alt="Currency View" width="200" height="300" /></a><p class="wp-caption-text">Currency View</p></div>
<div id="attachment_94" class="wp-caption alignnone" style="width: 210px"><a href="http://lumenovis.com/wp-content/uploads/2009/02/screenshot-20090225-112253.png"><img class="size-medium wp-image-94" title="screenshot-20090225-112253" src="http://lumenovis.com/wp-content/uploads/2009/02/screenshot-20090225-112253-200x300.png" alt="Zone Scheduler View" width="200" height="300" /></a><p class="wp-caption-text">Zone Scheduler View</p></div>
]]></content:encoded>
			<wfw:commentRss>http://lumenovis.com/2009/02/25/iphone-conversion-application/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>iPhone Directory Search Application</title>
		<link>http://lumenovis.com/2009/02/10/iphone-directory-search-application/</link>
		<comments>http://lumenovis.com/2009/02/10/iphone-directory-search-application/#comments</comments>
		<pubDate>Tue, 10 Feb 2009 20:36:58 +0000</pubDate>
		<dc:creator>Dan</dc:creator>
				<category><![CDATA[iPhone]]></category>
		<category><![CDATA[GPS]]></category>
		<category><![CDATA[Objective C]]></category>
		<category><![CDATA[REST]]></category>
		<category><![CDATA[XML]]></category>

		<guid isPermaLink="false">http://lumenovis.com/?p=98</guid>
		<description><![CDATA[I just finished a contract app called &#8220;BizFinder&#8221; that searches a set of business directories based on the location of the user. This app required extensive XML processing and a number of REST operations, integration with Google Maps (both remote server and local app), and use of the onboard GPS capability. This is version 1- [...]]]></description>
			<content:encoded><![CDATA[<p>I just finished a contract app called &#8220;BizFinder&#8221; that searches a set of business directories based on the location of the user.  This app required extensive XML processing and a number of REST operations, integration with Google Maps (both remote server and local app), and use of the onboard GPS capability.</p>
<p>This is version 1- version 2 will have a host of new features and user friendly options.</p>
<p>Here are some screen shots (more to follow):</p>
<div id="attachment_114" class="wp-caption alignnone" style="width: 210px"><a href="http://lumenovis.com/wp-content/uploads/2009/02/screenshot-20090225-113209.png"><img class="size-medium wp-image-114" title="screenshot-20090225-113209" src="http://lumenovis.com/wp-content/uploads/2009/02/screenshot-20090225-113209-200x300.png" alt="Search Page" width="200" height="300" /></a><p class="wp-caption-text">Search Page</p></div>
]]></content:encoded>
			<wfw:commentRss>http://lumenovis.com/2009/02/10/iphone-directory-search-application/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Code Snippet &#8211; iPhone SqlLite DBO</title>
		<link>http://lumenovis.com/2009/01/20/code-snippet-iphone-sqllite-dbo/</link>
		<comments>http://lumenovis.com/2009/01/20/code-snippet-iphone-sqllite-dbo/#comments</comments>
		<pubDate>Tue, 20 Jan 2009 17:05:07 +0000</pubDate>
		<dc:creator>Dan</dc:creator>
				<category><![CDATA[iPhone]]></category>
		<category><![CDATA[DBO]]></category>
		<category><![CDATA[Objective C]]></category>
		<category><![CDATA[ORM]]></category>
		<category><![CDATA[Sqlite]]></category>

		<guid isPermaLink="false">http://lumenovis.com/?p=84</guid>
		<description><![CDATA[I&#8217;ve been developing database applications for years and I&#8217;ve welcomed the advances in abstraction that have allowed me to focus more on value-added business logic and less on low-level database access routines (with associated pitfalls). So it was a jarring &#8220;back to the past&#8221; slap in the face when I started developing on the iPhone [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been developing database applications for years and I&#8217;ve welcomed the advances in abstraction that have allowed me to focus more on value-added business logic and less on low-level database access routines (with associated pitfalls).  So it was a jarring &#8220;back to the past&#8221; slap in the face when I started developing on the iPhone and Sqlite&#8230; once again, we (the developers) are required to manage all of the details of the database and write all of the plumbing required to marshall data to and from the database.</p>
<p>I looked for an ORM solution and found EntropyDB and SQLitePersistentObjects&#8230; the former requires a license for use in commercial applications, and the latter was quite immature when I first looked at it (though it appears to have move forward significantly and is worth another look).  While it would be challenging and fun to develop a &#8220;Hibernate for iPhone&#8221;, I simply didn&#8217;t have the time, but I figured I could leverage the &#8220;80/20&#8243; rule and get most of the benefit with minimal effort.  So I created a couple of base classes that, with minimal custom configuration, make any Objective C object into a &#8220;pseudo-DBO&#8221;.  Here&#8217;s the source- use it as you see fit.  (Note: This is an early version and has not been exhaustively tested, so keep that in mind.  And yes, I know there is a great deal that could be done with Protocols and other Objective C capabilities that would significantly improve this concept&#8230; this is something that&#8217;s grown organically and I hope to someday get around to cleaning it up.)</p>
<p>Basically- extend DatabaseObject in any object you want to have persisted, implement the &#8220;abstract&#8221; methods, and start using it.  Pretty straight forward.</p>
<p>Here&#8217;s an example of usage:<br />
&#8212;&#8212;<br />
Workout* workout = [[Workout alloc] init];<br />
workout.name = @&#8221;Workout 1&#8243;;<br />
workout.notes = @&#8221;some desc&#8221;;<br />
workout.startTime = [NSDate date];<br />
[workout persist];<br />
[[DBWrapper getInstance] databaseDump];</p>
<p>Workout* w2 = [Workout findById:workout.localId];<br />
NSInteger res = [Workout countAll];<br />
NSArray* res2 = [Workout findWhere:@"name = \"Medium workout\""];<br />
&#8212;-</p>
<p>DatabaseObject.h<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;</p>
<p>#import<br />
#import</p>
<p>@interface DatabaseObject : NSObject {<br />
NSInteger localId;<br />
NSDate* createdDate;<br />
NSDate* modifiedDate;<br />
BOOL isDirty;<br />
}</p>
<p>// abstract methods<br />
+ (NSString*) generateCreateSql;<br />
+ (NSString*) getTableName;<br />
- (NSString*) generateInsertSql;<br />
- (NSString*) generateUpdateSql;<br />
- (NSString*) generateDeleteSql;<br />
+ (id) constructDboFromResults:(sqlite3_stmt*)stmt;<br />
+ (void) test;</p>
<p>// props<br />
@property (readwrite) NSInteger localId;<br />
@property (readwrite) BOOL isDirty;<br />
@property (readwrite, retain) NSDate* createdDate;<br />
@property (readwrite, retain) NSDate* modifiedDate;</p>
<p>// methods<br />
+ (void) createTable:(BOOL)dropFirst;<br />
- (void) persist;<br />
- (void) unpersist;<br />
+ (id) findById:(NSInteger)id;<br />
+ (NSArray*) findAll;<br />
+ (NSArray*) findWhere:(NSString*)where;<br />
+ (NSInteger) countAll;<br />
+ (NSInteger) countWhere:(NSString*)where;</p>
<p>@end</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p>DatabaseObject.m<br />
&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
#import &#8220;DatabaseObject.h&#8221;<br />
#import &#8220;DBWrapper.h&#8221;</p>
<p>@interface DatabaseObject()<br />
+ (int) executeSql:(NSString*)sql;<br />
+ (void) executeQuery:(sqlite3_stmt*)stmt sql:(NSString*)sql;<br />
@end</p>
<p>@implementation DatabaseObject<br />
@synthesize localId, isDirty, createdDate, modifiedDate;</p>
<p>- (id) init<br />
{<br />
[super init];<br />
self.localId = -1;<br />
self.createdDate = nil;<br />
self.modifiedDate = nil;<br />
return self;<br />
}</p>
<p>- (void) dealloc<br />
{<br />
self.localId = -1;<br />
self.createdDate = nil;<br />
self.modifiedDate = nil;<br />
[super dealloc];<br />
}</p>
<p>+ (void) createTable:(BOOL)dropFirst<br />
{<br />
NSLog(@&#8221;DatabaseObject::createTable %@&#8221;, [self getTableName]);<br />
NSMutableString* sql = nil;<br />
if (dropFirst) {<br />
NSLog(@&#8221;dropping table&#8221;);<br />
sql = [[NSMutableString alloc] init];<br />
[sql appendString:@"DROP TABLE \""];<br />
[sql appendString:[self getTableName]];<br />
[sql appendString:@"\""];<br />
@try{<br />
[DatabaseObject executeSql:sql];<br />
}<br />
@catch (NSException* e) {<br />
NSLog(@&#8221;Exception caught dropping table: %@&#8221;, e);<br />
}<br />
}</p>
<p>sql = [self generateCreateSql];<br />
[DatabaseObject executeSql:sql];</p>
<p>}</p>
<p>- (void) persist<br />
{<br />
NSLog(@&#8221;DatabaseObject::persist&#8221;);<br />
if (self.localId &lt; 0) {<br />
NSLog(@&#8221;insert&#8221;);<br />
self.createdDate = [NSDate date];<br />
self.modifiedDate = [NSDate date];</p>
<p>NSString *sql = [self generateInsertSql];<br />
self.localId = [DatabaseObject executeSql:sql];<br />
} else {<br />
NSLog(@&#8221;update&#8221;);<br />
self.modifiedDate = [NSDate date];</p>
<p>NSString *sql = [self generateUpdateSql];<br />
[DatabaseObject executeSql:sql];<br />
}<br />
}</p>
<p>- (void) unpersist<br />
{<br />
NSLog(@&#8221;DatabaseObject::unpersist&#8221;);<br />
NSString* sql = [self generateDeleteSql];<br />
[DatabaseObject executeSql:sql];</p>
<p>}</p>
<p>+ (id) findById:(NSInteger)id<br />
{<br />
NSLog(@&#8221;DatabaseObject::findById %d&#8221;, id);<br />
NSString* sql = [[NSString alloc] initWithFormat:@&#8221;SELECT * FROM %@ WHERE id=%i&#8221;, [self getTableName], id];<br />
sqlite3_stmt* stmt = nil;<br />
if(sqlite3_prepare_v2([[DBWrapper getInstance] database], [sql UTF8String], -1, &amp;stmt, NULL) != SQLITE_OK) {<br />
[NSException raise:@"DatabaseException" format:@"Error while creating statement. '%s'", sqlite3_errmsg([[DBWrapper getInstance] database])];<br />
}<br />
if (sqlite3_step(stmt) == SQLITE_ROW) {<br />
return [self constructDboFromResults:stmt];<br />
}<br />
else<br />
{<br />
return  nil;<br />
}<br />
}</p>
<p>+ (NSArray*) findAll<br />
{<br />
NSLog(@&#8221;DatabaseObject::findAll&#8221;);<br />
NSString* sql = [[NSString alloc] initWithFormat:@&#8221;SELECT * FROM %@&#8221;, [self getTableName]];<br />
sqlite3_stmt* stmt = nil;<br />
if(sqlite3_prepare_v2([[DBWrapper getInstance] database], [sql UTF8String], -1, &amp;stmt, NULL) != SQLITE_OK) {<br />
[NSException raise:@"DatabaseException" format:@"Error while creating statement. '%s'", sqlite3_errmsg([[DBWrapper getInstance] database])];<br />
}<br />
NSMutableArray* res = [[NSMutableArray alloc] init];<br />
while (sqlite3_step(stmt) == SQLITE_ROW) {<br />
[res addObject:[self constructDboFromResults:stmt]];<br />
}<br />
return res;<br />
}</p>
<p>+ (NSArray*) findWhere:(NSString*)where<br />
{<br />
NSLog(@&#8221;DatabaseObject::findWhere %@&#8221;, where);<br />
NSString* sql = [[NSString alloc] initWithFormat:@&#8221;SELECT * FROM %@ WHERE %@&#8221;, [self getTableName], where];<br />
sqlite3_stmt* stmt = nil;<br />
if(sqlite3_prepare_v2([[DBWrapper getInstance] database], [sql UTF8String], -1, &amp;stmt, NULL) != SQLITE_OK) {<br />
[NSException raise:@"DatabaseException" format:@"Error while creating statement. '%s'", sqlite3_errmsg([[DBWrapper getInstance] database])];<br />
}<br />
NSMutableArray* res = [[NSMutableArray alloc] init];<br />
while (sqlite3_step(stmt) == SQLITE_ROW) {<br />
[res addObject:[self constructDboFromResults:stmt]];<br />
}<br />
return res;<br />
}</p>
<p>+ (NSInteger) countAll<br />
{<br />
NSLog(@&#8221;DatabaseObject::countAll&#8221;);<br />
return [self countWhere:@"1"];<br />
}</p>
<p>+ (NSInteger) countWhere:(NSString*)where<br />
{<br />
NSLog(@&#8221;DatabaseObject::countWhere %@&#8221;, where);<br />
NSString* sql = [[NSString alloc] initWithFormat:@&#8221;SELECT COUNT(*) FROM %@ WHERE %@&#8221;,[self getTableName], where];<br />
sqlite3_stmt *stmt;<br />
if (sqlite3_prepare_v2([[DBWrapper getInstance] database], [sql UTF8String], -1, &amp;stmt, NULL) != SQLITE_OK) {<br />
[NSException raise:@"DatabaseException" format:@"Error while creating statement. '%s'", sqlite3_errmsg([[DBWrapper getInstance] database])];<br />
}</p>
<p>if (sqlite3_step(stmt) == SQLITE_ROW) {<br />
NSInteger res = sqlite3_column_int(stmt, 0);<br />
NSLog(@&#8221;DatabaseObject::countWhere returning %d&#8221;, res);<br />
return res;<br />
}<br />
else<br />
{<br />
NSLog(@&#8221;DatabaseObject::countWhere: could not get count err=%s for sql %@&#8221;, sqlite3_errmsg([[DBWrapper getInstance] database]), sql);<br />
}<br />
return -1;</p>
<p>}</p>
<p>#pragma mark utils<br />
+ (int) executeSql:(NSString*)sql<br />
{<br />
NSLog(@&#8221;DBWrapper::executeSql: executing %@&#8221;, sql);<br />
sqlite3_stmt* stmt = nil;<br />
if(sqlite3_prepare_v2([[DBWrapper getInstance] database], [sql UTF8String], -1, &amp;stmt, NULL) != SQLITE_OK) {<br />
[NSException raise:@"DatabaseException" format:@"Error while creating statement. '%s'", sqlite3_errmsg([[DBWrapper getInstance] database])];<br />
}</p>
<p>if (SQLITE_DONE != sqlite3_step(stmt)) {<br />
NSLog(@&#8221;DBWrapper::executeSql: sql failed; %s&#8221;, sqlite3_errmsg([[DBWrapper getInstance] database]));</p>
<p>//Reset the add statement.<br />
sqlite3_reset(stmt);</p>
<p>[NSException raise:@"DatabaseException" format:@"Error while executing sql statement. '%s'", sqlite3_errmsg([[DBWrapper getInstance] database])];<br />
}<br />
else<br />
{<br />
NSLog(@&#8221;DBWrapper::executeSql: success&#8221;);</p>
<p>//Reset the add statement.<br />
sqlite3_reset(stmt);</p>
<p>return sqlite3_last_insert_rowid([[DBWrapper getInstance] database]);<br />
}<br />
return -1;<br />
}</p>
<p>+ (void) executeQuery:(sqlite3_stmt*)stmt sql:(NSString*)sql<br />
{<br />
NSLog(@&#8221;DBWrapper::executeQuery: executing %@&#8221;, sql);<br />
if(sqlite3_prepare_v2([[DBWrapper getInstance] database], [sql UTF8String], -1, &amp;stmt, NULL) != SQLITE_OK) {<br />
[NSException raise:@"DatabaseException" format:@"Error while creating statement. '%s'", sqlite3_errmsg([[DBWrapper getInstance] database])];<br />
}</p>
<p>}</p>
<p>@end<br />
&#8212;&#8212;&#8212;&#8212;&#8211;</p>
<p>DBWrapper.h<br />
&#8212;&#8212;&#8212;&#8212;&#8211;<br />
#import<br />
#import</p>
<p>@interface DBWrapper : NSObject {<br />
sqlite3* database;<br />
}</p>
<p>+(DBWrapper*) getInstance;</p>
<p>- (BOOL) openDatabase;<br />
- (void) closeDatabase;<br />
- (void) databaseDump;<br />
- (NSString*) nsStringFromResult:(sqlite3_stmt*)res column:(unsigned)col;</p>
<p>- (void) setDatabase:(sqlite3*)db;<br />
- (sqlite3*) database;</p>
<p>@end<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</p>
<p>DBWrapper.m<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
#import &#8220;DBWrapper.h&#8221;</p>
<p>@interface DBWrapper()<br />
- (NSString *) getDBPath;<br />
- (void) createDatabaseIfNeeded;<br />
@end</p>
<p>@implementation DBWrapper</p>
<p>- (void) setDatabase:(sqlite3*)db {<br />
database = db;<br />
}</p>
<p>- (sqlite3*) database {<br />
return database;<br />
}</p>
<p>static DBWrapper *INSTANCE = nil;</p>
<p>+ (DBWrapper *)getInstance<br />
{<br />
//	@synchronized(self)<br />
//	{<br />
if (!INSTANCE) {<br />
INSTANCE = [[[DBWrapper alloc] init] retain];<br />
}<br />
return INSTANCE;<br />
//	}<br />
//	return nil;<br />
}</p>
<p>- (BOOL) openDatabase {<br />
NSLog(@&#8221;opening database&#8221;);<br />
[self createDatabaseIfNeeded];<br />
if (sqlite3_open([[self getDBPath] UTF8String], &amp;database) == SQLITE_OK) {<br />
NSLog(@&#8221;database open&#8221;);<br />
sqlite3_extended_result_codes(database, 1);<br />
return YES;<br />
}<br />
else {<br />
sqlite3_close(database); //Even though the open call failed, close the database connection to release all the memory.<br />
return NO;<br />
}<br />
}</p>
<p>- (void) closeDatabase {<br />
NSLog(@&#8221;closing database&#8221;);<br />
if(database) {<br />
sqlite3_close(database);<br />
}<br />
}</p>
<p>#pragma mark utils</p>
<p>- (NSString *) getDBPath {</p>
<p>//Search for standard documents using NSSearchPathForDirectoriesInDomains<br />
//First Param = Searching the documents directory<br />
//Second Param = Searching the Users directory and not the System<br />
//Expand any tildes and identify home directories.<br />
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);<br />
NSString *documentsDir = [paths objectAtIndex:0];<br />
return [documentsDir stringByAppendingPathComponent:@"com.lumenova.workouttracker.sqlite"];<br />
}</p>
<p>- (void) createDatabaseIfNeeded {</p>
<p>//Using NSFileManager we can perform many file system operations.<br />
NSFileManager *fileManager = [NSFileManager defaultManager];<br />
NSError *error;<br />
NSString *dbPath = [self getDBPath];<br />
BOOL success = [fileManager fileExistsAtPath:dbPath];</p>
<p>if(!success) {<br />
success = [fileManager createFileAtPath:dbPath contents:[NSData data] attributes:nil ];<br />
if (!success)<br />
NSAssert1(0, @&#8221;Failed to create writable database file with message &#8216;%@&#8217;.&#8221;, [error localizedDescription]);<br />
}<br />
}</p>
<p>- (NSString*) nsStringFromResult:(sqlite3_stmt*)res column:(unsigned)col {<br />
char* string = (char *)sqlite3_column_text(res, col);<br />
if (string == NULL) {<br />
return nil;<br />
} else {<br />
return [NSString stringWithUTF8String:string];<br />
}<br />
}</p>
<p>- (void) databaseDump {<br />
NSLog(@&#8221;databaseDump&#8221;);<br />
sqlite3_stmt* stmt = nil;<br />
NSString* sql = @&#8221;SELECT name FROM sqlite_master WHERE type=&#8217;table&#8217; ORDER BY name&#8221;;<br />
if(sqlite3_prepare_v2(database, [sql UTF8String], -1, &amp;stmt, NULL) != SQLITE_OK) {<br />
NSAssert1(0, @&#8221;Error while creating statement. &#8216;%s&#8217;&#8221;, sqlite3_errmsg(database));<br />
}</p>
<p>while (sqlite3_step(stmt) == SQLITE_ROW) {<br />
NSString* tableName = [self nsStringFromResult:stmt column:0];<br />
NSLog(@&#8221;TABLE: %@&#8221;, tableName);</p>
<p>sqlite3_stmt* stmt2 = nil;<br />
NSString* sql2 = [[[NSString alloc] initWithFormat: @&#8221;SELECT * FROM %@&#8221;, tableName] autorelease];<br />
if(sqlite3_prepare_v2(database, [sql2 UTF8String], -1, &amp;stmt2, NULL) != SQLITE_OK) {<br />
NSAssert1(0, @&#8221;Error while creating statement. &#8216;%s&#8217;&#8221;, sqlite3_errmsg(database));<br />
}<br />
int cols = sqlite3_column_count(stmt2);<br />
for (int i = 0; i &lt; cols; i++) {<br />
// can get names here with sqlite3_column_name<br />
}</p>
<p>while (sqlite3_step(stmt2) == SQLITE_ROW) {<br />
NSMutableString* sb = [[[NSMutableString alloc] init] autorelease];<br />
[sb appendString:@"  row:"];<br />
for (int i = 0; i &lt; cols; i++) {<br />
NSString* ret = [self nsStringFromResult:stmt2 column:i];<br />
if (ret == nil) {<br />
[sb appendString:@"NULL"];<br />
} else {<br />
[sb appendString: ret];<br />
}<br />
if (i &lt; (cols &#8211; 1)) {<br />
[sb appendString:@", "];<br />
}<br />
}<br />
NSLog(sb);<br />
}</p>
<p>}</p>
<p>}</p>
<p>@end<br />
&#8212;&#8212;&#8212;&#8212;&#8212;</p>
<p>Example of a class the extends the DBO:<br />
&#8212;&#8212;&#8212;&#8212;&#8212;<br />
#import &#8220;StrengthSet.h&#8221;<br />
#import &#8220;DBWrapper.h&#8221;</p>
<p>@implementation StrengthSet<br />
@synthesize exerciseId, reps, weight, notes, hint;</p>
<p>- (id) init<br />
{<br />
[super init];<br />
self.reps = 0;<br />
self.weight = 0.0;<br />
self.notes = nil;<br />
self.exerciseId = -1;<br />
self.hint = MAINTAIN;<br />
return self;<br />
}</p>
<p>- (void) dealloc<br />
{<br />
self.notes = nil;<br />
[super dealloc];<br />
}</p>
<p>#pragma mark DBO methods<br />
+(NSString*) getTableName {<br />
return @&#8221;strength_set&#8221;;<br />
}</p>
<p>+ (NSString*) generateCreateSql<br />
{<br />
NSMutableString* sql = [[NSMutableString alloc] initWithFormat:@&#8221;CREATE TABLE \&#8221;%@\&#8221; (&#8220;, [StrengthSet getTableName]];<br />
// DBO<br />
[sql appendString:@"\"id\" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, \"created_date\" INTEGER NOT NULL, \"modified_date\" INTEGER NOT NULL"];<br />
[sql appendString:@", "];<br />
// Exercise<br />
[sql appendString:@"\"exercise_id\" INTEGER NOT NULL, \"reps\" INTEGER NOT NULL, \"weight\" REAL NOT NULL, \"hint\" INTEGER NOT NULL, \"notes\" TEXT"];<br />
[sql appendString:@")"];<br />
return sql;<br />
}</p>
<p>- (NSString*) generateInsertSql<br />
{<br />
NSInteger now = [[NSDate date] timeIntervalSince1970];<br />
NSString* sql = [[[NSString alloc] initWithFormat:@&#8221;INSERT INTO %@ (created_date, modified_date, exercise_id, reps, weight, hint, notes) VALUES (%i, %i, %i, %i, %f, %i, \&#8221;%@\&#8221;)&#8221;,<br />
[StrengthSet getTableName],<br />
now,<br />
now,<br />
self.exerciseId,<br />
self.reps,<br />
self.weight,<br />
self.hint,<br />
self.notes ] autorelease];<br />
return sql;<br />
}</p>
<p>- (NSString*) generateUpdateSql<br />
{<br />
NSInteger now = [[NSDate date] timeIntervalSince1970];<br />
NSMutableString* sql = [[NSMutableString alloc] initWithFormat:@&#8221;UPDATE %@ SET modified_date=%d, exercise_id=%d, reps=%d, weight=%f, hint=%d, notes=\&#8217;%@\&#8217;&#8221;,<br />
[StrengthSet getTableName],<br />
now,<br />
self.exerciseId,<br />
self.reps,<br />
self.weight,<br />
self.hint,<br />
self.notes];<br />
[sql appendFormat:@" WHERE id=%d", self.localId];</p>
<p>return sql;</p>
<p>}</p>
<p>- (NSString*) generateDeleteSql<br />
{<br />
return [[NSString alloc] initWithFormat:@&#8221;DELETE FROM %@ WHERE id=%i&#8221;, [StrengthSet getTableName], self.localId];<br />
}</p>
<p>+ (id) constructDboFromResults:(sqlite3_stmt*)stmt<br />
{<br />
NSLog(@&#8221;StrengthExercise::constructDboFromResults&#8221;);</p>
<p>StrengthSet* result = [[[StrengthSet alloc] init] autorelease];<br />
result.localId = sqlite3_column_int(stmt, 0);<br />
result.createdDate = [NSDate dateWithTimeIntervalSince1970:sqlite3_column_int(stmt, 1)];<br />
result.modifiedDate = [NSDate dateWithTimeIntervalSince1970:sqlite3_column_int(stmt, 2)];<br />
result.exerciseId = sqlite3_column_int(stmt, 3);<br />
result.reps = sqlite3_column_int(stmt, 4);<br />
result.weight = sqlite3_column_double(stmt, 5);<br />
result.hint = sqlite3_column_int(stmt, 6);<br />
result.notes = [[DBWrapper getInstance] nsStringFromResult:stmt column:7];</p>
<p>return result;</p>
<p>}</p>
<p>@end<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;</p>
]]></content:encoded>
			<wfw:commentRss>http://lumenovis.com/2009/01/20/code-snippet-iphone-sqllite-dbo/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
