<?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-7028181408582795486</id><updated>2011-10-20T22:27:35.742+13:00</updated><category term='c#'/><category term='remote control'/><category term='dunit'/><category term='delphi programming'/><category term='iphone'/><category term='excel'/><category term='lightspeed'/><category term='python'/><category term='vmware'/><category term='garbage collection'/><category term='winphone7'/><category term='MonoTouch'/><category term='.net'/><category term='Mono'/><category term='version control'/><category term='nunit unittesting'/><category term='virtual box'/><category term='iphone development'/><category term='tiopf'/><category term='virtual machines'/><category term='sql server'/><category term='database'/><category term='delphi'/><title type='text'>Coding with the enemy</title><subtitle type='html'>Mostly delphi and database programming with the occasional rant</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>44</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-9211641021869540479</id><published>2011-08-04T16:50:00.004+12:00</published><updated>2011-08-04T17:17:48.344+12:00</updated><title type='text'>Delphi for iOS!</title><content type='html'>I attended the Rad Studio World Tour today in Auckland.  Delphi XE2 has some nice features (x64, &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;OSX&lt;/span&gt;, &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;FireMonkey&lt;/span&gt;) but the standout for me was the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;iOS&lt;/span&gt; support.&lt;br /&gt;&lt;br /&gt;Developing for the iPhone &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;et&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;al&lt;/span&gt; is mostly a pain in the proverbial.  &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;XCode&lt;/span&gt; is somewhat of a mess and Objective C was designed by someone with an unholy fetish for square brackets.  The last time I did iPhone &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;dev&lt;/span&gt;, I did most of my coding in c++ on Windows and only booted into OSX for deployment and testing on the iPhone.&lt;br /&gt;&lt;br /&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;Embarcadero&lt;/span&gt; are looking to fix that with Delphi XE2.  You can write and test your code in Delphi on Windows.  When you need to try it on &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;iOS&lt;/span&gt;, you create a &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;xcode&lt;/span&gt; project (1 mouse click, only needed once) and then boot into OSX and open the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_10"&gt;xcode&lt;/span&gt; project there.  From &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_11"&gt;xcode&lt;/span&gt; you can edit, compile, run and debug your 100% &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_12"&gt;Delphi&lt;/span&gt; code.  If you have either Windows or OSX in a virtual machine you can flick from one &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_13"&gt;tother&lt;/span&gt; as you wish.  Yor app can be compiled and run in both Windows and iOS.&lt;br /&gt;&lt;br /&gt;Awesome!&lt;br /&gt;&lt;br /&gt;It's not all perfect, &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_14"&gt;xcode&lt;/span&gt; is still there, &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_15"&gt;OSX&lt;/span&gt; is a must and the whole code signing is probably as irritating as before, but it's much better than the objective c alternative.  It only works with new apps written using FireMonkey but you will be able to pull in older code.&lt;br /&gt;&lt;br /&gt;The &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_16"&gt;iOS&lt;/span&gt; app is full native code, with access to hardware such as &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_17"&gt;gps&lt;/span&gt;, &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_18"&gt;accelerometer&lt;/span&gt;  and camera.&lt;br /&gt;&lt;br /&gt;Note: Accessing the phone hardware means that your app will no longer run under windows due to either the hardware or the support units not being there.  I suspect that this is resolvable with some conditional defines and a bit of hacking.&lt;br /&gt;&lt;br /&gt;Much to my supprise I am now excited again; both about delphi programming and about iOS programming.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-9211641021869540479?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/9211641021869540479/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=9211641021869540479' title='14 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/9211641021869540479'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/9211641021869540479'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2011/08/delphi-for-ios.html' title='Delphi for iOS!'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>14</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-8981322951607019583</id><published>2011-06-11T14:44:00.002+12:00</published><updated>2011-06-11T14:54:53.506+12:00</updated><title type='text'>Delphi image components, ImageEn has a new home</title><content type='html'>If you have used image editing and manipulation in delphi, there is a good change you have used or heard of ImageEn components.  I have used them in my photo printing program, &lt;a href="http://www.picsprint.com/"&gt;Pics Print&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The ImageEn component suite has now moved to delphi shareware company &lt;a href="http://www.xequte.com/"&gt;Xequte&lt;/a&gt;.  You can find them at &lt;a href="http://www.xequte.com/imageen/"&gt;www.xequte.com/imageen&lt;/a&gt; or at &lt;!--[if gte mso 9]&gt;&lt;xml&gt;  &lt;w:worddocument&gt;   &lt;w:view&gt;Normal&lt;/w:View&gt;   &lt;w:zoom&gt;0&lt;/w:Zoom&gt;   &lt;w:trackmoves/&gt;   &lt;w:trackformatting/&gt;   &lt;w:punctuationkerning/&gt;   &lt;w:validateagainstschemas/&gt;   &lt;w:saveifxmlinvalid&gt;false&lt;/w:SaveIfXMLInvalid&gt;   &lt;w:ignoremixedcontent&gt;false&lt;/w:IgnoreMixedContent&gt;   &lt;w:alwaysshowplaceholdertext&gt;false&lt;/w:AlwaysShowPlaceholderText&gt;   &lt;w:donotpromoteqf/&gt;   &lt;w:lidthemeother&gt;EN-NZ&lt;/w:LidThemeOther&gt;   &lt;w:lidthemeasian&gt;X-NONE&lt;/w:LidThemeAsian&gt;   &lt;w:lidthemecomplexscript&gt;X-NONE&lt;/w:LidThemeComplexScript&gt;   &lt;w:compatibility&gt;    &lt;w:breakwrappedtables/&gt;    &lt;w:snaptogridincell/&gt;    &lt;w:wraptextwithpunct/&gt;    &lt;w:useasianbreakrules/&gt;    &lt;w:dontgrowautofit/&gt;    &lt;w:splitpgbreakandparamark/&gt;    &lt;w:enableopentypekerning/&gt;    &lt;w:dontflipmirrorindents/&gt;    &lt;w:overridetablestylehps/&gt;   &lt;/w:Compatibility&gt;   &lt;w:browserlevel&gt;MicrosoftInternetExplorer4&lt;/w:BrowserLevel&gt;   &lt;m:mathpr&gt;    &lt;m:mathfont val="Cambria Math"&gt;    &lt;m:brkbin val="before"&gt;    &lt;m:brkbinsub val="&amp;#45;-"&gt;    &lt;m:smallfrac val="off"&gt;    &lt;m:dispdef/&gt;    &lt;m:lmargin val="0"&gt;    &lt;m:rmargin val="0"&gt;    &lt;m:defjc val="centerGroup"&gt;    &lt;m:wrapindent val="1440"&gt;    &lt;m:intlim val="subSup"&gt;    &lt;m:narylim val="undOvr"&gt;   &lt;/m:mathPr&gt;&lt;/w:WordDocument&gt; &lt;/xml&gt;&lt;![endif]--&gt;&lt;!--[if gte mso 9]&gt;&lt;xml&gt;  &lt;w:latentstyles deflockedstate="false" defunhidewhenused="true" defsemihidden="true" defqformat="false" defpriority="99" latentstylecount="267"&gt;   &lt;w:lsdexception locked="false" priority="0" semihidden="false" unhidewhenused="false" qformat="true" name="Normal"&gt;   &lt;w:lsdexception locked="false" priority="9" semihidden="false" unhidewhenused="false" qformat="true" name="heading 1"&gt;   &lt;w:lsdexception locked="false" priority="9" qformat="true" name="heading 2"&gt;   &lt;w:lsdexception locked="false" priority="9" qformat="true" name="heading 3"&gt;   &lt;w:lsdexception locked="false" priority="9" qformat="true" name="heading 4"&gt;   &lt;w:lsdexception locked="false" priority="9" qformat="true" name="heading 5"&gt;   &lt;w:lsdexception locked="false" priority="9" qformat="true" name="heading 6"&gt;   &lt;w:lsdexception locked="false" priority="9" qformat="true" name="heading 7"&gt;   &lt;w:lsdexception locked="false" priority="9" qformat="true" name="heading 8"&gt;   &lt;w:lsdexception locked="false" priority="9" qformat="true" name="heading 9"&gt;   &lt;w:lsdexception locked="false" priority="39" name="toc 1"&gt;   &lt;w:lsdexception locked="false" priority="39" name="toc 2"&gt;   &lt;w:lsdexception locked="false" priority="39" name="toc 3"&gt;   &lt;w:lsdexception locked="false" priority="39" name="toc 4"&gt;   &lt;w:lsdexception locked="false" priority="39" name="toc 5"&gt;   &lt;w:lsdexception locked="false" priority="39" name="toc 6"&gt;   &lt;w:lsdexception locked="false" priority="39" name="toc 7"&gt;   &lt;w:lsdexception locked="false" priority="39" name="toc 8"&gt;   &lt;w:lsdexception locked="false" priority="39" name="toc 9"&gt;   &lt;w:lsdexception locked="false" priority="35" qformat="true" name="caption"&gt;   &lt;w:lsdexception locked="false" priority="10" semihidden="false" unhidewhenused="false" qformat="true" name="Title"&gt;   &lt;w:lsdexception locked="false" priority="1" name="Default Paragraph Font"&gt;   &lt;w:lsdexception locked="false" priority="11" semihidden="false" unhidewhenused="false" qformat="true" name="Subtitle"&gt;   &lt;w:lsdexception locked="false" priority="22" semihidden="false" unhidewhenused="false" qformat="true" name="Strong"&gt;   &lt;w:lsdexception locked="false" priority="20" semihidden="false" unhidewhenused="false" qformat="true" name="Emphasis"&gt;   &lt;w:lsdexception locked="false" priority="59" semihidden="false" unhidewhenused="false" name="Table Grid"&gt;   &lt;w:lsdexception locked="false" unhidewhenused="false" name="Placeholder Text"&gt;   &lt;w:lsdexception locked="false" priority="1" semihidden="false" unhidewhenused="false" qformat="true" name="No Spacing"&gt;   &lt;w:lsdexception locked="false" priority="60" semihidden="false" unhidewhenused="false" name="Light Shading"&gt;   &lt;w:lsdexception locked="false" priority="61" semihidden="false" unhidewhenused="false" name="Light List"&gt;   &lt;w:lsdexception locked="false" priority="62" semihidden="false" unhidewhenused="false" name="Light Grid"&gt;   &lt;w:lsdexception locked="false" priority="63" semihidden="false" unhidewhenused="false" name="Medium Shading 1"&gt;   &lt;w:lsdexception locked="false" priority="64" semihidden="false" unhidewhenused="false" name="Medium Shading 2"&gt;   &lt;w:lsdexception locked="false" priority="65" semihidden="false" unhidewhenused="false" name="Medium List 1"&gt;   &lt;w:lsdexception locked="false" priority="66" semihidden="false" unhidewhenused="false" name="Medium List 2"&gt;   &lt;w:lsdexception locked="false" priority="67" semihidden="false" unhidewhenused="false" name="Medium Grid 1"&gt;   &lt;w:lsdexception locked="false" priority="68" semihidden="false" unhidewhenused="false" name="Medium Grid 2"&gt;   &lt;w:lsdexception locked="false" priority="69" semihidden="false" unhidewhenused="false" name="Medium Grid 3"&gt;   &lt;w:lsdexception locked="false" priority="70" semihidden="false" unhidewhenused="false" name="Dark List"&gt;   &lt;w:lsdexception locked="false" priority="71" semihidden="false" unhidewhenused="false" name="Colorful Shading"&gt;   &lt;w:lsdexception locked="false" priority="72" semihidden="false" unhidewhenused="false" name="Colorful List"&gt;   &lt;w:lsdexception locked="false" priority="73" semihidden="false" unhidewhenused="false" name="Colorful Grid"&gt;   &lt;w:lsdexception locked="false" priority="60" semihidden="false" unhidewhenused="false" name="Light Shading Accent 1"&gt;   &lt;w:lsdexception locked="false" priority="61" semihidden="false" unhidewhenused="false" name="Light List Accent 1"&gt;   &lt;w:lsdexception locked="false" priority="62" semihidden="false" unhidewhenused="false" name="Light Grid Accent 1"&gt;   &lt;w:lsdexception locked="false" priority="63" semihidden="false" unhidewhenused="false" name="Medium Shading 1 Accent 1"&gt;   &lt;w:lsdexception locked="false" priority="64" semihidden="false" unhidewhenused="false" name="Medium Shading 2 Accent 1"&gt;   &lt;w:lsdexception locked="false" priority="65" semihidden="false" unhidewhenused="false" name="Medium List 1 Accent 1"&gt;   &lt;w:lsdexception locked="false" unhidewhenused="false" name="Revision"&gt;   &lt;w:lsdexception locked="false" priority="34" semihidden="false" unhidewhenused="false" qformat="true" name="List Paragraph"&gt;   &lt;w:lsdexception locked="false" priority="29" semihidden="false" unhidewhenused="false" qformat="true" name="Quote"&gt;   &lt;w:lsdexception locked="false" priority="30" semihidden="false" unhidewhenused="false" qformat="true" name="Intense Quote"&gt;   &lt;w:lsdexception locked="false" priority="66" semihidden="false" unhidewhenused="false" name="Medium List 2 Accent 1"&gt;   &lt;w:lsdexception locked="false" priority="67" semihidden="false" unhidewhenused="false" name="Medium Grid 1 Accent 1"&gt;   &lt;w:lsdexception locked="false" priority="68" semihidden="false" unhidewhenused="false" name="Medium Grid 2 Accent 1"&gt;   &lt;w:lsdexception locked="false" priority="69" semihidden="false" unhidewhenused="false" name="Medium Grid 3 Accent 1"&gt;   &lt;w:lsdexception locked="false" priority="70" semihidden="false" unhidewhenused="false" name="Dark List Accent 1"&gt;   &lt;w:lsdexception locked="false" priority="71" semihidden="false" unhidewhenused="false" name="Colorful Shading Accent 1"&gt;   &lt;w:lsdexception locked="false" priority="72" semihidden="false" unhidewhenused="false" name="Colorful List Accent 1"&gt;   &lt;w:lsdexception locked="false" priority="73" semihidden="false" unhidewhenused="false" name="Colorful Grid Accent 1"&gt;   &lt;w:lsdexception locked="false" priority="60" semihidden="false" unhidewhenused="false" name="Light Shading Accent 2"&gt;   &lt;w:lsdexception locked="false" priority="61" semihidden="false" unhidewhenused="false" name="Light List Accent 2"&gt;   &lt;w:lsdexception locked="false" priority="62" semihidden="false" unhidewhenused="false" name="Light Grid Accent 2"&gt;   &lt;w:lsdexception locked="false" priority="63" semihidden="false" unhidewhenused="false" name="Medium Shading 1 Accent 2"&gt;   &lt;w:lsdexception locked="false" priority="64" semihidden="false" unhidewhenused="false" name="Medium Shading 2 Accent 2"&gt;   &lt;w:lsdexception locked="false" priority="65" semihidden="false" unhidewhenused="false" name="Medium List 1 Accent 2"&gt;   &lt;w:lsdexception locked="false" priority="66" semihidden="false" unhidewhenused="false" name="Medium List 2 Accent 2"&gt;   &lt;w:lsdexception locked="false" priority="67" semihidden="false" unhidewhenused="false" name="Medium Grid 1 Accent 2"&gt;   &lt;w:lsdexception locked="false" priority="68" semihidden="false" unhidewhenused="false" name="Medium Grid 2 Accent 2"&gt;   &lt;w:lsdexception locked="false" priority="69" semihidden="false" unhidewhenused="false" name="Medium Grid 3 Accent 2"&gt;   &lt;w:lsdexception locked="false" priority="70" semihidden="false" unhidewhenused="false" name="Dark List Accent 2"&gt;   &lt;w:lsdexception locked="false" priority="71" semihidden="false" unhidewhenused="false" name="Colorful Shading Accent 2"&gt;   &lt;w:lsdexception locked="false" priority="72" semihidden="false" unhidewhenused="false" name="Colorful List Accent 2"&gt;   &lt;w:lsdexception locked="false" priority="73" semihidden="false" unhidewhenused="false" name="Colorful Grid Accent 2"&gt;   &lt;w:lsdexception locked="false" priority="60" semihidden="false" unhidewhenused="false" name="Light Shading Accent 3"&gt;   &lt;w:lsdexception locked="false" priority="61" semihidden="false" unhidewhenused="false" name="Light List Accent 3"&gt;   &lt;w:lsdexception locked="false" priority="62" semihidden="false" unhidewhenused="false" name="Light Grid Accent 3"&gt;   &lt;w:lsdexception locked="false" priority="63" semihidden="false" unhidewhenused="false" name="Medium Shading 1 Accent 3"&gt;   &lt;w:lsdexception locked="false" priority="64" semihidden="false" unhidewhenused="false" name="Medium Shading 2 Accent 3"&gt;   &lt;w:lsdexception locked="false" priority="65" semihidden="false" unhidewhenused="false" name="Medium List 1 Accent 3"&gt;   &lt;w:lsdexception locked="false" priority="66" semihidden="false" unhidewhenused="false" name="Medium List 2 Accent 3"&gt;   &lt;w:lsdexception locked="false" priority="67" semihidden="false" unhidewhenused="false" name="Medium Grid 1 Accent 3"&gt;   &lt;w:lsdexception locked="false" priority="68" semihidden="false" unhidewhenused="false" name="Medium Grid 2 Accent 3"&gt;   &lt;w:lsdexception locked="false" priority="69" semihidden="false" unhidewhenused="false" name="Medium Grid 3 Accent 3"&gt;   &lt;w:lsdexception locked="false" priority="70" semihidden="false" unhidewhenused="false" name="Dark List Accent 3"&gt;   &lt;w:lsdexception locked="false" priority="71" semihidden="false" unhidewhenused="false" name="Colorful Shading Accent 3"&gt;   &lt;w:lsdexception locked="false" priority="72" semihidden="false" unhidewhenused="false" name="Colorful List Accent 3"&gt;   &lt;w:lsdexception locked="false" priority="73" semihidden="false" unhidewhenused="false" name="Colorful Grid Accent 3"&gt;   &lt;w:lsdexception locked="false" priority="60" semihidden="false" unhidewhenused="false" name="Light Shading Accent 4"&gt;   &lt;w:lsdexception locked="false" priority="61" semihidden="false" unhidewhenused="false" name="Light List Accent 4"&gt;   &lt;w:lsdexception locked="false" priority="62" semihidden="false" unhidewhenused="false" name="Light Grid Accent 4"&gt;   &lt;w:lsdexception locked="false" priority="63" semihidden="false" unhidewhenused="false" name="Medium Shading 1 Accent 4"&gt;   &lt;w:lsdexception locked="false" priority="64" semihidden="false" unhidewhenused="false" name="Medium Shading 2 Accent 4"&gt;   &lt;w:lsdexception locked="false" priority="65" semihidden="false" unhidewhenused="false" name="Medium List 1 Accent 4"&gt;   &lt;w:lsdexception locked="false" priority="66" semihidden="false" unhidewhenused="false" name="Medium List 2 Accent 4"&gt;   &lt;w:lsdexception locked="false" priority="67" semihidden="false" unhidewhenused="false" name="Medium Grid 1 Accent 4"&gt;   &lt;w:lsdexception locked="false" priority="68" semihidden="false" unhidewhenused="false" name="Medium Grid 2 Accent 4"&gt;   &lt;w:lsdexception locked="false" priority="69" semihidden="false" unhidewhenused="false" name="Medium Grid 3 Accent 4"&gt;   &lt;w:lsdexception locked="false" priority="70" semihidden="false" unhidewhenused="false" name="Dark List Accent 4"&gt;   &lt;w:lsdexception locked="false" priority="71" semihidden="false" unhidewhenused="false" name="Colorful Shading Accent 4"&gt;   &lt;w:lsdexception locked="false" priority="72" semihidden="false" unhidewhenused="false" name="Colorful List Accent 4"&gt;   &lt;w:lsdexception locked="false" priority="73" semihidden="false" unhidewhenused="false" name="Colorful Grid Accent 4"&gt;   &lt;w:lsdexception locked="false" priority="60" semihidden="false" unhidewhenused="false" name="Light Shading Accent 5"&gt;   &lt;w:lsdexception locked="false" priority="61" semihidden="false" unhidewhenused="false" name="Light List Accent 5"&gt;   &lt;w:lsdexception locked="false" priority="62" semihidden="false" unhidewhenused="false" name="Light Grid Accent 5"&gt;   &lt;w:lsdexception locked="false" priority="63" semihidden="false" unhidewhenused="false" name="Medium Shading 1 Accent 5"&gt;   &lt;w:lsdexception locked="false" priority="64" semihidden="false" unhidewhenused="false" name="Medium Shading 2 Accent 5"&gt;   &lt;w:lsdexception locked="false" priority="65" semihidden="false" unhidewhenused="false" name="Medium List 1 Accent 5"&gt;   &lt;w:lsdexception locked="false" priority="66" semihidden="false" unhidewhenused="false" name="Medium List 2 Accent 5"&gt;   &lt;w:lsdexception locked="false" priority="67" semihidden="false" unhidewhenused="false" name="Medium Grid 1 Accent 5"&gt;   &lt;w:lsdexception locked="false" priority="68" semihidden="false" unhidewhenused="false" name="Medium Grid 2 Accent 5"&gt;   &lt;w:lsdexception locked="false" priority="69" semihidden="false" unhidewhenused="false" name="Medium Grid 3 Accent 5"&gt;   &lt;w:lsdexception locked="false" priority="70" semihidden="false" unhidewhenused="false" name="Dark List Accent 5"&gt;   &lt;w:lsdexception locked="false" priority="71" semihidden="false" unhidewhenused="false" name="Colorful Shading Accent 5"&gt;   &lt;w:lsdexception locked="false" priority="72" semihidden="false" unhidewhenused="false" name="Colorful List Accent 5"&gt;   &lt;w:lsdexception locked="false" priority="73" semihidden="false" unhidewhenused="false" name="Colorful Grid Accent 5"&gt;   &lt;w:lsdexception locked="false" priority="60" semihidden="false" unhidewhenused="false" name="Light Shading Accent 6"&gt;   &lt;w:lsdexception locked="false" priority="61" semihidden="false" unhidewhenused="false" name="Light List Accent 6"&gt;   &lt;w:lsdexception locked="false" priority="62" semihidden="false" unhidewhenused="false" name="Light Grid Accent 6"&gt;   &lt;w:lsdexception locked="false" priority="63" semihidden="false" unhidewhenused="false" name="Medium Shading 1 Accent 6"&gt;   &lt;w:lsdexception locked="false" priority="64" semihidden="false" unhidewhenused="false" name="Medium Shading 2 Accent 6"&gt;   &lt;w:lsdexception locked="false" priority="65" semihidden="false" unhidewhenused="false" name="Medium List 1 Accent 6"&gt;   &lt;w:lsdexception locked="false" priority="66" semihidden="false" unhidewhenused="false" name="Medium List 2 Accent 6"&gt;   &lt;w:lsdexception locked="false" priority="67" semihidden="false" unhidewhenused="false" name="Medium Grid 1 Accent 6"&gt;   &lt;w:lsdexception locked="false" priority="68" semihidden="false" unhidewhenused="false" name="Medium Grid 2 Accent 6"&gt;   &lt;w:lsdexception locked="false" priority="69" semihidden="false" unhidewhenused="false" name="Medium Grid 3 Accent 6"&gt;   &lt;w:lsdexception locked="false" priority="70" semihidden="false" unhidewhenused="false" name="Dark List Accent 6"&gt;   &lt;w:lsdexception locked="false" priority="71" semihidden="false" unhidewhenused="false" name="Colorful Shading Accent 6"&gt;   &lt;w:lsdexception locked="false" priority="72" semihidden="false" unhidewhenused="false" name="Colorful List Accent 6"&gt;   &lt;w:lsdexception locked="false" priority="73" semihidden="false" unhidewhenused="false" name="Colorful Grid Accent 6"&gt;   &lt;w:lsdexception locked="false" priority="19" semihidden="false" unhidewhenused="false" qformat="true" name="Subtle Emphasis"&gt;   &lt;w:lsdexception locked="false" priority="21" semihidden="false" unhidewhenused="false" qformat="true" name="Intense Emphasis"&gt;   &lt;w:lsdexception locked="false" priority="31" semihidden="false" unhidewhenused="false" qformat="true" name="Subtle Reference"&gt;   &lt;w:lsdexception locked="false" priority="32" semihidden="false" unhidewhenused="false" qformat="true" name="Intense Reference"&gt;   &lt;w:lsdexception locked="false" priority="33" semihidden="false" unhidewhenused="false" qformat="true" name="Book Title"&gt;   &lt;w:lsdexception locked="false" priority="37" name="Bibliography"&gt;   &lt;w:lsdexception locked="false" priority="39" qformat="true" name="TOC Heading"&gt;  &lt;/w:LatentStyles&gt; &lt;/xml&gt;&lt;![endif]--&gt;&lt;!--[if gte mso 10]&gt; &lt;style&gt;  /* Style Definitions */  table.MsoNormalTable  {mso-style-name:"Table Normal";  mso-tstyle-rowband-size:0;  mso-tstyle-colband-size:0;  mso-style-noshow:yes;  mso-style-priority:99;  mso-style-parent:"";  mso-padding-alt:0cm 5.4pt 0cm 5.4pt;  mso-para-margin:0cm;  mso-para-margin-bottom:.0001pt;  mso-pagination:widow-orphan;  font-size:10.0pt;  font-family:"Times New Roman","serif";} &lt;/style&gt; &lt;![endif]--&gt;&lt;a href="http://www.imageen.com/"&gt;www.imageen.com&lt;/a&gt;.  If you want to see the components in action, download demos from &lt;a href="http://www.xequte.com/imageen/download/Index.html#Demos"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.xequte.com/imageen/graphics/home_build_apps.gif"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 671px; height: 550px;" src="http://www.xequte.com/imageen/graphics/home_build_apps.gif" alt="" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-8981322951607019583?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/8981322951607019583/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=8981322951607019583' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/8981322951607019583'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/8981322951607019583'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2011/06/delphi-image-components-imageen-has-new.html' title='Delphi image components, ImageEn has a new home'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-4701299229321971325</id><published>2011-03-09T12:26:00.001+13:00</published><updated>2011-03-11T20:02:39.156+13:00</updated><title type='text'>Helpful tips for US based developers AKA Short date time is evil</title><content type='html'>English is a bit like html. There is a standard, but not everyone understands it, and there are a number of slightly incompatible implementations.&lt;br /&gt;&lt;br /&gt;This is most obvious in spoken English where accents, and idioms vary wildly causing mutual incomprehension.&lt;br /&gt;&lt;br /&gt;The last time I was in the USA, I had the following conversation in a restaurant:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Me: Can I have a coke please&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Waitress: I’m sorry, what did you want?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Me: A coca cola please&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Waitress: I &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;didn&lt;/span&gt;’t quite get that. What did you want?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Me (using the British technique of speaking slowly and loudly so the natives understand): A COCA COLA PLEASE&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Waitress (getting quite testy): What?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Me: Can I have a Pepsi?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Waitress: I’m sorry, we don’t have Pepsi. Would you like a coke?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;English as she is wrote.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The problem with the World Wide Web is the worldwide part of it. Whatever you write, will probably be read by people from a different country. Even if your audience is English speaking, there are enough differences between countries for confusion and irritation to creep in.&lt;br /&gt;&lt;br /&gt;A few examples:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;   Last year, Steam had a &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;pre&lt;/span&gt; release offer for a game due to be released on 10/12/10(or similar). When is that? My natural reading was Dec 10, but it may have been Oct 12. There was no way of telling without trying to divine the writer’s intentions and country of residence.&lt;/li&gt;&lt;li&gt;Last month, I evaluated several &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;rss&lt;/span&gt; readers for Win Phone 7.  The first one I looked at had the dates &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;hardcoded&lt;/span&gt; as mm/dd.  If the author had just used the standard system formatting, it would have been correct and less work.&lt;/li&gt;&lt;li&gt;I also looked at The Weather Channel for Win Phone 7.  There was a setting to use metric units.  However even with this selected some (but not all) temperatures were shown in Fahrenheit.  As an added bonus, the tile would sometimes show a temperature of -18.  &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;Hawkes&lt;/span&gt; Bay hasn't seen -18 since the last ice age.&lt;/li&gt;&lt;li&gt;In Blogger post options, the Post date is in m/d/yy format&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;So what do (mostly)US websites and applications frequently get wrong?&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;Dates&lt;/span&gt;&lt;br /&gt;Short date time is evil! Repeat that and make it a mantra.&lt;br /&gt;&lt;br /&gt;Most of the countries I have visited use dd/mm/&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;yy&lt;/span&gt;. The USA uses mm/dd/&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;yy&lt;/span&gt;. I believe some countries use &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;yy&lt;/span&gt;/mm/dd, but don't quote me on that.&lt;br /&gt;&lt;br /&gt;The upshot is that a date such as 09/10/11 is entirely ambiguous without context. Even if the date has some hints, such as 09/17/11, I still have to stop and parse the date rather than reading it. When reading, I devote less than a 1/10 of a second per word. Having to stop, figure out the date, and then start up again seriously screws up my reading.&lt;br /&gt;&lt;br /&gt;It's even worse when entering dates, now I have even more opportunity for screwing up. Fortunately most sites have moved to date time pickers or separate day/month/year boxes. Not all have though, one site I was on today used a single edit box with a helpful "dd/mm/&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;yyyy&lt;/span&gt;" label beside it.&lt;br /&gt;&lt;br /&gt;Blogs and articles frequently refer to seasons.  I.e. the new gadget is due in Summer 2011.&lt;br /&gt;This is still problematic; our seasons are about 5.5 months out from the USA so that requires a certain amount of adjustment.&lt;br /&gt;&lt;br /&gt;As for the holiday season, &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;WTF&lt;/span&gt;? I had to ask an American friend for clarification.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;"in general US holiday season means from Thanksgiving (3rd Thursday in November) to the day after new year’s day"&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;That's not what I would have guessed. If we had a holiday season here, it would start just before Christmas and extend till late Jan. No-one would release anything then, we are all on holiday.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Measurement units&lt;/span&gt;&lt;br /&gt;When it comes to measures, there is the US still soldiering on with the Imperial system, and pretty much everyone else is on metric. Unfortunately many sites and applications use just the Imperial measures which is at best an aggravation and at worst requires a quick unit conversion with Google, or more likely, a move onto a different site/app.&lt;br /&gt;&lt;br /&gt;Now I understand feet and inches in small quantities provided I don't need to be accurate. Miles require a mental conversion so it has to be something important before I will bother with the maths. After that, I get lost quite quickly.&lt;br /&gt;&lt;br /&gt;Ounces are awkward. To my uncertain knowledge, the only people around here who still use ounces are those engaged in buying and selling small amounts of dope. This is not at all useful in performing conversions. &lt;span style="font-style: italic;"&gt;Update: I have been reliably informed that the local drug dealers have moved on and now sell in metric units and/or dollar units (e.g. a $250 bag).&lt;/span&gt; Pounds are the same as ounces, only more so.&lt;br /&gt;&lt;br /&gt;Don't get me started on fluid ounces. I have absolutely no idea how big a fluid ounce is, and no desire to know. This has caused me some aggravation in the past; "How big a drink should I have? Well 60 oz sounds small..."&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Number formats&lt;/span&gt;&lt;br /&gt;Most countries use "," as the thousand separator and "." as the decimal separator. A few however have it the other way round.  Some use spaces for a separator, and the Romans don't even use &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_10"&gt;Arabic&lt;/span&gt; &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_11"&gt;numerals&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;What to do?&lt;/span&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Don't hard code date formats.  I use 'dd &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_12"&gt;mmm&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_13"&gt;yyyy&lt;/span&gt;' in &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_14"&gt;written&lt;/span&gt; text.  In my web applications, I mostly use 'dd &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_15"&gt;mmm&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_16"&gt;yyyy&lt;/span&gt;'.  When I use the system short date time then I make sure that I also use &lt;a href="http://msdn.microsoft.com/en-us/library/hy4kkhe0.aspx"&gt;asp.net globalisation settings&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;Don't hard code number formats either.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Test with multiple cultures.  I generally test with NZ and US cultures for dates.  I also use Norway or Sweden for testing number formatting.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Why am I picking on the Americans?&lt;/span&gt;&lt;br /&gt;American based programmers seem to the be worst offenders.  There are 2 main reasons for this:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;The USA is a large part of the English speaking market, too large to be ignored for developers outside it.  Anyone wanting to sell software into there needs to take account of the US language and units.  The reverse is not &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_17"&gt;necessarily&lt;/span&gt; true.&lt;/li&gt;&lt;li&gt;Observational bias.  If someone was to &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_18"&gt;hardcode&lt;/span&gt; metric and dd/mm/&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_19"&gt;yyyy&lt;/span&gt; in their applications, I would never notice.&lt;/li&gt;&lt;/ol&gt;&lt;span style="font-weight: bold;"&gt;Update&lt;/span&gt;&lt;br /&gt;I didn't put my location in the original post; my point is that you should write and program so that others can understand regardless of your, and their, location.  Nonetheless, for those that are interested, I live and work in &lt;a href="http://www.hawkesbaynz.com/"&gt;Hawkes Bay, New Zealand&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-4701299229321971325?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/4701299229321971325/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=4701299229321971325' title='21 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/4701299229321971325'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/4701299229321971325'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2010/02/helpful-tips-for-us-based-developers.html' title='Helpful tips for US based developers AKA Short date time is evil'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>21</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-8673455588127324455</id><published>2010-12-17T14:28:00.004+13:00</published><updated>2010-12-20T21:43:40.060+13:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='winphone7'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><title type='text'>Developing on the Win phone 7 hardware without a developer account</title><content type='html'>Microsoft have released a free toolset for developing Windows Phone 7 applications.  However you cannot debug or deploy onto actual hardware until you create a developer account @ $99 per year.&lt;br /&gt;&lt;br /&gt;In my case, I only have a demo phone for 2 weeks so a developer account seems like a waste of money.&lt;br /&gt;&lt;br /&gt;To work around this restriction, you need to do the following:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;1 Unlock the phone:&lt;/span&gt;&lt;br /&gt;Download and install the Chevron unlocker and certificate from &lt;a href="http://forum.xda-developers.com/showthread.php?t=857127"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;2 Stop the phone from relocking every time you reboot&lt;/span&gt;&lt;br /&gt;Edit your hosts file (C:\Windows\System32\drivers\etc\hosts)&lt;br /&gt;Add the line&lt;br /&gt;&lt;span style="font-style: italic;"&gt;127.0.0.1 developerservices.windowsphone.com&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;You can now deploy and debug on your phone.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Note&lt;/span&gt;:  the phone will still relock itself every couple of weeks, giving the following error&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;“[application name] has been revoked by Microsoft. Please uninstall it.”&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Just rerun Chevron and unlock again.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;2nd note&lt;/span&gt;:  You can deploy your .xap file to others and they can run them on unlocked phones.  However the continual relocking may get annoying.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;3rd note&lt;/span&gt;:  You can't use Chevron to pirate applications.  It will only allow you to run unsigned applications.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-8673455588127324455?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/8673455588127324455/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=8673455588127324455' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/8673455588127324455'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/8673455588127324455'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2010/12/developing-on-win-phone-7-hardware.html' title='Developing on the Win phone 7 hardware without a developer account'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-8939874122108327557</id><published>2010-12-13T09:48:00.004+13:00</published><updated>2010-12-18T08:16:30.887+13:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='winphone7'/><category scheme='http://www.blogger.com/atom/ns#' term='virtual machines'/><category scheme='http://www.blogger.com/atom/ns#' term='vmware'/><title type='text'>Developing for Windows Phone 7 in a virtual machine</title><content type='html'>According to Microsoft, installing the windows phone developer tools into a virtual machine is not supported.  This is because the phone emulator is itself a virtual machine and, as Inception has shown, running a virtual machine inside a virtual machine gets really slow.  The emulator also requires DirectX 10 for XNA develoment, and current virtual machines only offer DirectX9.&lt;br /&gt;&lt;br /&gt;However I do all my development in virtual machines.  I already have a VM setup with VS2010, version control, database etc.  I don't fancy setting that up all over again just for a phone, particularly one that I only have for 2 weeks.&lt;br /&gt;&lt;br /&gt;Time to do some testing...&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Virtual PC&lt;/span&gt;&lt;br /&gt;Running the dev tools in a Windows 7 Virtual PC works (or rather fails to work) as advertised.  While I could create and compile a phone project, I couldn't actually run it in the emulator.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;VMWare&lt;/span&gt;&lt;br /&gt;Using a VMware vm was much better.  I could compile and run a silverlight project on the emulator.  On my laptop, the emulator performance was dire.  On my desktop however, emulator performance was adequate but not stunning.&lt;br /&gt;&lt;br /&gt;On either machine, XNA projects wouldn't run on the emulator due to the lack of DirectX 10.  They would compile but trying to deploy would fail with "&lt;span style="font-style: italic;"&gt;The current display adapter does not meet the emulator requirements to run XNA Framework applications&lt;/span&gt;."&lt;br /&gt;&lt;br /&gt;However deploying and running on a real phone worked fine.  Both Silverlight and XNA deployed and ran without any issues.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Booting from a virtual hard drive&lt;/span&gt; (thanks Paul)&lt;br /&gt;Should work but requires Windows 7.  See &lt;a href="http://www.hanselman.com/blog/LessVirtualMoreMachineWindows7AndTheMagicOfBootToVHD.aspx"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;TL;DR&lt;/span&gt;&lt;br /&gt;You can develop Silverlight applications in a VMWare virtual machine, testing against the emulator (slow) or actual hardware (fast).  You can develop XNA applications in a VMWare vm but you need to deploy to actual hardware.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Useful links&lt;/span&gt;&lt;br /&gt;Microsoft's free tools: &lt;a href="http://create.msdn.com/en-US/"&gt;Create App hub&lt;/a&gt;&lt;br /&gt;Charles Petzold giant ebook:  &lt;a href="http://www.microsoft.com/downloads/en/details.aspx?FamilyID=bb8f5eb6-8214-4387-bf02-f78f314a74eb"&gt;Programming Windows Phone 7&lt;/a&gt;&lt;br /&gt;Reddit Win Phone 7 section: &lt;a href="http://www.reddit.com/r/wp7dev/"&gt;http://www.reddit.com/r/wp7dev/&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-8939874122108327557?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/8939874122108327557/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=8939874122108327557' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/8939874122108327557'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/8939874122108327557'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2010/12/developing-for-windows-phone-7-in.html' title='Developing for Windows Phone 7 in a virtual machine'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-7291991547765647391</id><published>2010-09-10T19:25:00.003+12:00</published><updated>2010-09-10T20:00:10.198+12:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='nunit unittesting'/><category scheme='http://www.blogger.com/atom/ns#' term='.net'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><title type='text'>.net Unit Testing 101</title><content type='html'>Links, slides and sample code from my .net Unit Testing 101 presentation.&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;a href="http://www.nunit.org/"&gt;NUnit - unit testing library &lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.testdriven.net/"&gt;TestDriven.net - Visual Studio integration&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.mindscape.co.nz/products/LightSpeed/default.aspx"&gt;Lightspeed ORM&lt;/a&gt; Free or full version is needed to run the sample code&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.pragprog.com/titles/utc2/pragmatic-unit-testing-in-c-with-nunit"&gt;Pragmatic unit testing ebook&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.sourceitsoftware.com/download/UnitTesting101.zip"&gt;Presentation and code&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-7291991547765647391?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/7291991547765647391/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=7291991547765647391' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/7291991547765647391'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/7291991547765647391'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2010/09/net-unit-testing-101.html' title='.net Unit Testing 101'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-2715166480942109651</id><published>2010-03-22T21:41:00.011+13:00</published><updated>2010-03-29T07:52:49.260+13:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='winphone7'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><title type='text'>Windows Phone 7 - A party pack of sweets for developers</title><content type='html'>They are playing advertisements for &lt;a href="http://www.cadbury.co.nz/Products/Candy-Confectionery/Pascall-Party-Pack.aspx"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;Pascall's&lt;/span&gt;&lt;/span&gt; Party Pack&lt;/a&gt;  on TV at the moment.  The tag line is "All sweets you love, and one you can't stand."  That pretty much sums up Windows Phone 7 for developers.  Lots of goodness with a few things that may leave a  bad taste in your mouth.&lt;br /&gt;&lt;br /&gt;Despite the name, Windows Phone 7 Series is not a &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_1"&gt;successor&lt;/span&gt; to Windows Mobile 6.x.  Instead the name  is a marketing nod towards Windows 7.  Although both WP7 and WM6 are based on Windows CE, there is no resemblance at a higher level.  From a user point of view, WP7 is closer to the iPhone than to WM6.  A more accurate name would be Windows Phone 1.&lt;br /&gt;&lt;br /&gt;After far too much time reading, watching and playing, here are my thoughts on WP7 as relates to development:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Tasty:&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Development is done in c# and &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;Silverlight&lt;/span&gt;&lt;/span&gt;/&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;XNA&lt;/span&gt;&lt;/span&gt;.  While native code would be nice, C# is easier to get into than Objective C.  I haven't used either &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;Silverlight&lt;/span&gt;&lt;/span&gt; or &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;XNA&lt;/span&gt;&lt;/span&gt; previously but they look a lot more promising than the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;XP&lt;/span&gt;&lt;/span&gt; era Windows Forms used by Windows Mobile.&lt;/li&gt;&lt;li&gt;The tools are much better than those for the iPhone, and free&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Push notifications look at lot easier to do than on the iPhone&lt;/li&gt;&lt;li&gt;Apparently &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;xbox&lt;/span&gt;&lt;/span&gt; live integration is really good (I wouldn't know)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;There are metric &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;shitloads&lt;/span&gt;&lt;/span&gt; of tutorials, walk &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;throughs&lt;/span&gt;&lt;/span&gt; and documentation (Twitter apps are the new hello world)&lt;/li&gt;&lt;li&gt;Games programming looks really, really nice&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_10"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;Meh&lt;/span&gt;&lt;/span&gt;:&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The tools don't work well in virtual machines.  You can make it work in a Win 7 32bit &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_11"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_10"&gt;VM&lt;/span&gt;&lt;/span&gt; but it will run like a dog.  The tools don't work at all in Win 7 x64.  If you don't want to install onto your main system, you can try booting from a &lt;a href="http://www.hanselman.com/blog/LessVirtualMoreMachineWindows7AndTheMagicOfBootToVHD.aspx"&gt;virtual hard drive&lt;/a&gt;.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Yuck:&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;No database support (apparently it's not necessary &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_12"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_11"&gt;coz&lt;/span&gt;&lt;/span&gt; you have &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_13"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_12"&gt;xml&lt;/span&gt;&lt;/span&gt; and the cloud).  &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_14"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_13"&gt;SQL&lt;/span&gt;&lt;/span&gt; Server CE is built into the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_15"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_14"&gt;rom&lt;/span&gt;&lt;/span&gt;, but no access is provided.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;No multitasking (push notifications only)&lt;/li&gt;&lt;li&gt;No access to the file system.  Application files all go into Isolated Storage in the app folder.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;No "&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_16"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_15"&gt;sideloading&lt;/span&gt;&lt;/span&gt;" of applications.  Apps can only be installed from the Marketplace, or by Visual Studio&lt;/li&gt;&lt;li&gt;No built in file synchronisation (it's this cloud thing again).  &lt;/li&gt;&lt;li&gt;No &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_17"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_16"&gt;Silverlight&lt;/span&gt;&lt;/span&gt; support in Windows Mobile 6.x (but there is &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_18"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_17"&gt;Silverlight&lt;/span&gt;&lt;/span&gt; for &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_19"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_18"&gt;Symbian&lt;/span&gt;&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_20"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_19"&gt;wtf&lt;/span&gt;&lt;/span&gt;) and no Win forms support in WP7.  I.e. even if your win mobile app was written in c# it needs to be rewritten for WP7.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Limited &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_21"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_20"&gt;APIs&lt;/span&gt;&lt;/span&gt; (no access to contacts, no sockets, ...)&lt;/li&gt;&lt;li&gt;No native code - no c, c++, pascal etc (and thus &lt;a href="http://blog.pavlov.net/2010/03/22/stopping-development-for-windows-mobile/"&gt;no &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_22"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_21"&gt;firefox&lt;/span&gt;&lt;/span&gt; :(&lt;/a&gt;)&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;I haven't felt this conflicted since the &lt;a href="http://vfr1200online.com/index.php/vfr-1200/87-vfr-1200-f-first-ride-impressions.html"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_23"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_22"&gt;vfr&lt;/span&gt;&lt;/span&gt; 1200&lt;/a&gt;.  Some nice things balanced by some not so nice.&lt;br /&gt;&lt;br /&gt;As mentioned, so this is essentially version 1.  Some of the issues are planned to be fixed after the initial release (copy/paste, database access).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Links&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Microsoft&lt;/span&gt;&lt;br /&gt;&lt;a href="http://developer.windowsphone.com/windows-phone-7-series/"&gt;Windows Phone 7 tools&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ff431744%28VS.92%29.aspx"&gt;Code samples&lt;/a&gt;&lt;br /&gt;&lt;a href="http://developer.windowsphone.com/"&gt;Developer network&lt;/a&gt;&lt;br /&gt;&lt;a href="http://live.visitmix.com/videos"&gt;Mix10 videos (check out the keynote)&lt;br /&gt;&lt;/a&gt;&lt;a href="http://windowsteamblog.com/blogs/wpdev/archive/2010/03/18/windows-phone-7-series-ui-design-amp-interaction-guide.aspx?utm_source=twitterfeed&amp;amp;utm_medium=twitter"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_25"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_24"&gt;UI&lt;/span&gt;&lt;/span&gt; Guide&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_26"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_25"&gt;Silverlight&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;a href="http://10rem.net/articles/how-to-get-started-in-wpf-or-silverlight-a-learning-path-for-new-developers"&gt;Get started in &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_27"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_26"&gt;Silverlight&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://timheuer.com/blog/archive/2010/03/15/get-started-with-silverlight-for-windows-phone.aspx"&gt;Get started with &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_28"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_27"&gt;Silverlight&lt;/span&gt;&lt;/span&gt; in WM7&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Example apps&lt;/span&gt;&lt;br /&gt;&lt;a href="http://rodrigueh.com/post/WP7-DOTNET-Twitter-Client-for-Windows-Phone-7-with-Silverlight.aspx"&gt;Twitter client&lt;/a&gt;&lt;br /&gt;&lt;a href="http://weblogs.asp.net/scottgu/archive/2010/03/18/building-a-windows-phone-7-twitter-application-using-silverlight.aspx"&gt;Another twitter client (Scott &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_29"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_28"&gt;Gu&lt;/span&gt;&lt;/span&gt;)&lt;/a&gt;&lt;br /&gt;&lt;a href="http://blois.us/blog/2010/03/labyrinth-sample-for-windows-phone.html"&gt;Labyrinth&lt;/a&gt;&lt;br /&gt;&lt;a href="http://sviluppomobile.blogspot.com/2010/03/sqlite-for-wp-7-series-proof-of-concept.html"&gt;Sqlite database&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Blogs&lt;/span&gt;&lt;br /&gt;&lt;a href="http://www.artificialignorance.net/blog"&gt;Artificial Ignorance&lt;/a&gt;&lt;a href="http://10rem.net/articles/how-to-get-started-in-wpf-or-silverlight-a-learning-path-for-new-developers"&gt;&lt;br /&gt;&lt;/a&gt;&lt;a href="http://10rem.net/"&gt;10rem&lt;/a&gt;&lt;br /&gt;&lt;a href="http://sviluppomobile.blogspot.com/2010/03/sqlite-for-wp-7-series-proof-of-concept.html"&gt;Mobile development&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-2715166480942109651?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/2715166480942109651/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=2715166480942109651' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/2715166480942109651'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/2715166480942109651'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2010/03/windows-phone-7-party-pack-of-sweets.html' title='Windows Phone 7 - A party pack of sweets for developers'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-5338763023907342103</id><published>2010-02-13T13:20:00.006+13:00</published><updated>2010-02-14T18:19:03.420+13:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='delphi programming'/><category scheme='http://www.blogger.com/atom/ns#' term='virtual machines'/><category scheme='http://www.blogger.com/atom/ns#' term='delphi'/><category scheme='http://www.blogger.com/atom/ns#' term='vmware'/><title type='text'>Solving a  mid-life crisis with a Solid State Drive</title><content type='html'>My development laptop is now 18 months old, which makes it older than me in computer years.  As part of a mid-life refresh, I replaced the boot drive, (250gb 7200rpm) with an Intel X25M 160gb ssd.&lt;br /&gt;&lt;br /&gt;The result of this is that things are much snappier.  How much snappier?  I timed a few things of importance to me, booting my laptop and virtual machines, starting delphi and rebuilding a medium sized project (600,000 loc).&lt;br /&gt;&lt;br /&gt;Overall, using an ssd cut the times by an average of 39%.  Not too bad an improvement.  To put it another way, my "getting started" time (boot laptop, boot vm, start delphi) went from 6:05 to 3:37.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_g2tNCh4si2M/S3YIaxmoNYI/AAAAAAAADS0/TQyuUKnlZ9Q/s1600-h/ssd.jpg"&gt;&lt;img style="cursor: pointer; width: 400px; height: 241px;" src="http://4.bp.blogspot.com/_g2tNCh4si2M/S3YIaxmoNYI/AAAAAAAADS0/TQyuUKnlZ9Q/s400/ssd.jpg" alt="" id="BLOGGER_PHOTO_ID_5437542856181429634" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Edit:&lt;/span&gt;&lt;br /&gt;The Delphi 2007 install is screwed up somewhere.  It certainly never  used to take 3 minutes to start up:( but sometime last year it started  getting really slow.   I don't use that install or vm much so I haven't  bothered trying to sort it out.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-5338763023907342103?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/5338763023907342103/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=5338763023907342103' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/5338763023907342103'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/5338763023907342103'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2010/02/solving-mid-life-crisis-with-solid.html' title='Solving a  mid-life crisis with a Solid State Drive'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_g2tNCh4si2M/S3YIaxmoNYI/AAAAAAAADS0/TQyuUKnlZ9Q/s72-c/ssd.jpg' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-652428107200151968</id><published>2010-01-14T21:18:00.005+13:00</published><updated>2010-01-14T23:35:25.498+13:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lightspeed'/><category scheme='http://www.blogger.com/atom/ns#' term='.net'/><title type='text'>[.net] Using sql server full text searching with Mindscape's LightSpeed</title><content type='html'>&lt;span style="font-style: italic;"&gt;Advance warning: This post is only of use to people using Lightspeed or suffering from insomnia.   &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The problem&lt;/span&gt;&lt;br /&gt;For my current c# project, I am using &lt;a href="http://www.mindscape.co.nz/products/LightSpeed/default.aspx"&gt;Mindscape's Lightspeed&lt;/a&gt; O/R framework.  Lightspeed is a mighty fine product that makes object persistence a breeze.  I would kill to have this in delphi.&lt;br /&gt;&lt;br /&gt;However the only full text searching that LightSpeed supports out of the box is &lt;a href="http://incubator.apache.org/lucene.net/"&gt;Lucene.net&lt;/a&gt;.  Sql Server full text searching is not provided and no-one else seems to have created it.&lt;br /&gt;&lt;br /&gt;The good news is that Lightspeed has a pluggable search engine framework so it is possible to add a new search engine.  The bad news is that it's not overly well documented and there aren't many examples.  The good news is that their online support is &lt;a href="http://www.mindscape.co.nz/forums/Thread.aspx?ThreadID=2702"&gt;pretty good&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The resolution&lt;/span&gt;&lt;br /&gt;Mindscape have a &lt;a href="http://www.mindscape.co.nz/blog/index.php/2009/02/25/lightspeed-writing-a-custom-search-engine/"&gt;blog post&lt;/a&gt; outlining the process of adding a new search engine.  However there are a  number of traps for young players that aren't covered there, or indeed anywhere.  The following should shed some light on the process.&lt;br /&gt;&lt;br /&gt;Creating a new search engine requires implimenting ISearchEngine&lt;br /&gt;&lt;pre class="csharp"&gt;  &lt;span style="color: rgb(6, 0, 255);"&gt;public&lt;/span&gt; &lt;span style="color: rgb(6, 0, 255);"&gt;interface&lt;/span&gt; ISearchEngine&lt;br /&gt; &lt;span style="color: rgb(0, 0, 0);"&gt;{&lt;/span&gt;&lt;br /&gt;   IList&lt;span style="color: rgb(0, 0, 0);"&gt;&lt;&lt;/span&gt;SearchResult&lt;span style="color: rgb(0, 0, 0);"&gt;&gt;&lt;/span&gt; Search&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(6, 0, 255);"&gt;string&lt;/span&gt; query, &lt;span style="color: rgb(6, 0, 255);"&gt;params&lt;/span&gt; &lt;span style="color: rgb(6, 0, 255);"&gt;string&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;[&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;]&lt;/span&gt; scopes&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;;&lt;br /&gt;   &lt;span style="color: rgb(6, 0, 255);"&gt;void&lt;/span&gt; Add&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;IndexKey indexKey, &lt;span style="color: rgb(6, 0, 255);"&gt;string&lt;/span&gt; data&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;;&lt;br /&gt;   &lt;span style="color: rgb(6, 0, 255);"&gt;void&lt;/span&gt; Update&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;IndexKey indexKey, &lt;span style="color: rgb(6, 0, 255);"&gt;string&lt;/span&gt; data&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;;&lt;br /&gt;   &lt;span style="color: rgb(6, 0, 255);"&gt;void&lt;/span&gt; Remove&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;IndexKey indexKey&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;;&lt;br /&gt;   &lt;span style="color: rgb(6, 0, 255);"&gt;void&lt;/span&gt; Optimize&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;;&lt;br /&gt;   &lt;span style="color: rgb(6, 0, 255);"&gt;void&lt;/span&gt; Clear&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;;&lt;br /&gt;   LightSpeedContext Context &lt;span style="color: rgb(0, 0, 0);"&gt;{&lt;/span&gt; &lt;span style="color: rgb(6, 0, 255);"&gt;get&lt;/span&gt;; set; &lt;span style="color: rgb(0, 0, 0);"&gt;}&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: rgb(6, 0, 255);"&gt;void&lt;/span&gt; BeginBulkAdd&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;;&lt;br /&gt;   &lt;span style="color: rgb(6, 0, 255);"&gt;void&lt;/span&gt; EndBulkAdd&lt;span style="color: rgb(0, 0, 0);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;)&lt;/span&gt;;&lt;br /&gt; &lt;span style="color: rgb(0, 0, 0);"&gt;}&lt;/span&gt;&lt;/pre&gt;For sql server, and for most databases with inbuilt FTS, most of these methods can just be left as empty method bodies.  All that needs to be implemented is Context (stores lightspeed configuration info such as the database connection string) and Search.&lt;br /&gt;&lt;br /&gt;All that is needed to implement Context is:&lt;br /&gt;&lt;pre class="csharp"&gt;    public LightSpeedContext Context &lt;span style="color: rgb(0, 0, 0);"&gt;{&lt;/span&gt; &lt;span style="color: rgb(6, 0, 255);"&gt;get&lt;/span&gt;; set; &lt;span style="color: rgb(0, 0, 0);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&lt;/span&gt;&lt;/pre&gt; The fun comes in implementing Search:).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Example class&lt;/span&gt;&lt;br /&gt;LightSpeed takes a class and maps it to a database table.  In my case, the class is CmsModels.Entities.AccClaim.  It is stored in the table AccData and has an integer primary key called ClaimId.&lt;br /&gt;&lt;br /&gt;To perform a search, say finding all of my claims, I need to run the following query:&lt;br /&gt;&lt;pre class="csharp"&gt;    select *&lt;br /&gt;   from FreeTextTable(AccData, *, 'Sean Cross Prevshort')&lt;br /&gt;   order by RANK desc&lt;br /&gt;&lt;/pre&gt;returning something like&lt;br /&gt;&lt;pre class="csharp"&gt;    KEY       RANK&lt;br /&gt;   175671    27&lt;br /&gt;   175673    23&lt;br /&gt;   175646    15&lt;br /&gt;   175657    7&lt;br /&gt;&lt;/pre&gt;Key is the pk field (ClaimId) and Rank is how well the record matched the query.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Implimenting search&lt;/span&gt;&lt;br /&gt;The Search method takes a query ("Sean Cross Hastings") and an array of type names (["CmsModels.Entities.AccClaim", ...]).  It returns a list of SearchResult objects.  SearchResult has the following constructor:&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharp"&gt;    public SearchResult(&lt;br /&gt;        string key,&lt;br /&gt;        string scope,&lt;br /&gt;        string entityId,&lt;br /&gt;        float score&lt;br /&gt;   )&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&lt;/span&gt;&lt;/pre&gt; In short, we take the query and the class name, construct a query, run it and use the results to create a list of SearchResult objects.  Easy, in theory.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The devilish details&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;A   Getting the table name&lt;/span&gt;&lt;br /&gt;Given an object name, Lightspeed has a number of ways of determining the table name.  Which option is chosen depends on the model and class settings.&lt;br /&gt;The possibilities are&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Table name = class name (eg AccClaim)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Table name = pluralised class name (eg AccClaims)&lt;/li&gt;&lt;li&gt;Table name is explicitly set in class attributes (eg [Table("AccData", IdColumnName="ClaimID")])&lt;/li&gt;&lt;li&gt;Table name is set programmaticly using a user defined naming strategy object (eg TBL_ACCCLAIM)&lt;/li&gt;&lt;/ol&gt;AFAIAA It is not possible to cover all these cases without access to LightSpeed internals.  I have suggested that they provide a GetMyBloodyTableName method but that hasn't happened yet.&lt;br /&gt;&lt;br /&gt;I have opted to only support cases 1 and 3 as this covers most of my classes, and it's easy.  Any table name that falls into a different case can still be searched by specifying the table name explicitly.&lt;br /&gt;&lt;br /&gt;To get the table name, I look for a TableAttribute and use it.  If I can't find one, I use the type name.&lt;br /&gt;&lt;pre class="csharp"&gt;    string tableName = "";&lt;br /&gt;   Type t = Type.GetType(scope);&lt;br /&gt;   object[] tableAttrib = t.GetCustomAttributes(typeof(TableAttribute), false);&lt;br /&gt;   if (tableAttrib.Length &gt; 0)&lt;br /&gt;   {&lt;br /&gt;       tableName = ((TableAttribute)tableAttrib[0]).Name;&lt;br /&gt;   }&lt;br /&gt;   else          &lt;br /&gt;   {&lt;br /&gt;        tableName = t.Name.ToUpper();&lt;br /&gt;   }&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-style: italic;"&gt;B   Running the query&lt;/span&gt;&lt;br /&gt;LightSpeed doesn't support running random sql so it's back to ado.net.  The Context object  can be used to create a SqlCommand object so it's pretty straightforward:&lt;br /&gt; &lt;br /&gt;&lt;pre class="csharp"&gt;    IDbCommand command = Context.DataProviderObjectFactory.CreateCommand();           &lt;br /&gt;   Context.CreateUnitOfWork().PrepareCommand(command)           &lt;br /&gt;   command.CommandText = string.Format("select * from FreeTextTable([{0}], *, @query) order by RANK desc", tableName);           &lt;br /&gt;   ((SqlCommand)command).Parameters.AddWithValue("@query", query);           &lt;br /&gt;   IDataReader reader = command.ExecuteReader();               &lt;br /&gt;&lt;br /&gt;   while (reader.Read())               &lt;br /&gt;   {&lt;span style="font-family: Georgia,serif;"&gt;&lt;span style="font-family: monospace;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;       ...&lt;br /&gt;   }&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-style: italic;"&gt;C   Creating the SearchResult objects&lt;/span&gt;&lt;br /&gt;The SearchResult constructor is as follows:&lt;br /&gt;&lt;pre class="csharp"&gt;    public SearchResult(&lt;br /&gt;        string key,&lt;br /&gt;        string scope,&lt;br /&gt;        string entityId,&lt;br /&gt;        float score&lt;br /&gt;   )&lt;/pre&gt; &lt;span style="font-style: italic;"&gt;scope &lt;/span&gt;is the full class name passed into the Search method (eg "CmsModels.Entities.AccClaim")&lt;br /&gt;&lt;span style="font-style: italic;"&gt;entityId &lt;/span&gt;is the pk returned from the query in the Key field (eg 175671)&lt;br /&gt;&lt;span style="font-style: italic;"&gt;score &lt;/span&gt;is the rank returned from the query in the Rank field (eg 27)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;key &lt;/span&gt;is the problem child.  It is not properly explained anywhere in the documentation.  I only found out how it is created by creating a dummy Add method, putting a breakpoint in there and examining the values passed in.  It is a string in the format "{type name}]{entityId}" (eg "[AccClaim]175671").&lt;br /&gt;&lt;br /&gt;So creating the results is&lt;br /&gt;&lt;pre class="csharp"&gt;    while (reader.Read())&lt;br /&gt;   {&lt;br /&gt;       string entityId = reader[0].ToString();&lt;br /&gt;       int rank = reader.GetInt32(1);&lt;br /&gt;       string srKey = string.Format("[{0}]{1}", t.Name, entityId);&lt;br /&gt;       var sr = new SearchResult(srKey, scope, entityId, rank);&lt;br /&gt;       result.Add(sr);&lt;br /&gt;   }&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-weight: bold;"&gt;Use the source Luke&lt;/span&gt;&lt;br /&gt;The full source code is &lt;a href="http://www.mindscape.co.nz/forums/Post.aspx?ThreadID=2702&amp;amp;PostID=8325"&gt;here&lt;/a&gt;.  This is "works on my machine" quality code, so use with care.  In particular:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;It doesn't handle pluralisation or naming strategies&lt;/li&gt;&lt;li&gt;I cast directly to SqlCommand without testing it.  Works for me but..&lt;br /&gt;&lt;/li&gt;&lt;li&gt;It's not solidly tested.  I only use it for one table so it may do funny things with other table structures. &lt;br /&gt;&lt;/li&gt;&lt;li&gt;While running the code for the first time, the office power failed and the entire building went dark.  I'm not saying it's related, but if it happens to you, you are on your own.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;span style="font-weight: bold;"&gt;Things for MindScape to do&lt;/span&gt;&lt;br /&gt;Provide a GetMyBloodyTableName and GetMyBloodyKey helper methods.  Pretty please.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-652428107200151968?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/652428107200151968/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=652428107200151968' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/652428107200151968'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/652428107200151968'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2010/01/net-using-sql-server-full-text.html' title='[.net] Using sql server full text searching with Mindscape&apos;s LightSpeed'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-593975068367641533</id><published>2009-12-09T16:07:00.002+13:00</published><updated>2009-12-09T16:27:25.516+13:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><category scheme='http://www.blogger.com/atom/ns#' term='excel'/><title type='text'>Solving Excel's "DBCC TRACEON" error with brute force and ignorance</title><content type='html'>We use excel reports extensively for reporting.  They are fast to create and everyone can read and manipulate them.  However there are the occasional gotchas.  In the past, I have had to muck about with macros to fix &lt;a href="http://sourceitsoftware.blogspot.com/2009/08/changing-excel-query-connection-strings.html"&gt;connection string&lt;/a&gt; errors. &lt;br /&gt;&lt;br /&gt;We upgraded to sql server 2008 on the weekend.  Following that, nearly every data aware spreadsheet started giving "User 'public' does not have permission to run DBCC TRACEON" errors.&lt;br /&gt;&lt;br /&gt;The problem, and a resolution is described &lt;a href="http://www.fits-consulting.de/blog/PermaLink,guid,10259e27-75b2-4800-9b0b-0b526f556c10.aspx"&gt;here&lt;/a&gt;.    Older versions of Excel/MS query identified themselves by including APP=Microsoft® Query;" in the connection string.  MS also hard coded a check for "Microsoft® Query" in sql server which then runs DBCC TRACEON for no apparent reason.&lt;br /&gt;&lt;br /&gt;Under sql server 2000, this in fine, but under sql server 2008, this fails as DBCC requires admin permissions.&lt;br /&gt;&lt;br /&gt;The correct approach is change the connection string as described in the linked posts.  Previously I have done this with macros.  However this time I had 200+ spreadsheets to change :(.&lt;br /&gt;&lt;br /&gt;I used a free search and replace utility (&lt;a href="http://www.ecobyte.com/replacetext/"&gt;ReplaceText&lt;/a&gt;) to replace all instances of "APP=Microsoft® Query;" with "APP=Microsoft® WTFIT;".  2 important things here, the search and the replacement text are the same size, and the strings include "App=".  Failing to do either will give you a corrupt file.&lt;br /&gt;&lt;br /&gt;Problem solved in about an hour.  It's not a pretty solution but it's better than spending a week at it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-593975068367641533?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/593975068367641533/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=593975068367641533' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/593975068367641533'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/593975068367641533'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2009/12/solving-excels-dbcc-traceon-error-with.html' title='Solving Excel&apos;s &quot;DBCC TRACEON&quot; error with brute force and ignorance'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-9154135841281475949</id><published>2009-11-16T22:24:00.003+13:00</published><updated>2009-11-20T20:11:11.821+13:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='delphi'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><title type='text'>Why I am moving from delphi to .net</title><content type='html'>This post is somewhat of a conterpoint to &lt;a href="http://www.delphifeeds.com/go/s/62471"&gt;Why we didn’t convert to .Net. And perhaps we never will…&lt;/a&gt; I would have writen a post earlier, but I have spent most of the last week writing a tender proposal.  The tender was for a claims management application with 70 users scattered across the country.  My proposal was for a web application, using asp.net mvc and writen in c#.&lt;br /&gt;&lt;br /&gt;My main objection to the WoW post is not his (or her) conclusion, but the subtext that .net has nothing to offer. Delphi programmers (or at least the vocal ones hanging out in non-technical) seem to have a strong view on what "real' programming is, and .net fails on several points (not native code, garbage collected, large installation footprint) for these guys. My view is that "real" programming is solving problems, and using the best tools for the job. In some cases that is delphi, but increasingly for me it is c#.&lt;br /&gt;&lt;br /&gt;I haven't suddenly jumped ship, I reevaluated our (Catalyst's) needs earlier this year.  Two things came out of that; most of our futher development will be in web apps, and .net is a better fit for us.&lt;br /&gt;&lt;br /&gt;My and Catalyst's needs are not univeral.  I don't pretend that my reason for moving apply to everybody.  None the less, here are my reasons for moving:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Performance:  &lt;/span&gt;&lt;br /&gt;When it comes to performance, my most important benchmark is developer time.  As a (mostly) solo developer, I don't have enough time to do all the things that I want.  Anything that improves my productivity is good.  I find c# faster to develop in.&lt;br /&gt; &lt;br /&gt;From an runtime speed, it's hard to find good benchmarks.  My feeling is that Delphi is faster, but not enough to make a noticable difference in my kind of apps.  .net is let down by the winforms implimentation which (the last time I used it) had painfully slow drawing.  The rest of it is plenty fast enough.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Language features:&lt;br /&gt;&lt;/span&gt;Garbage collection and Linq.  You ever love them or hate them.  I love them.  Delphi has mostly caught up with the other big ticket items but not these.&lt;br /&gt;&lt;br /&gt;The standard library is another .net plus.  It may have an enormous footprint but it's certainly extensive.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Staffing:&lt;/span&gt;&lt;br /&gt;I work in a small city.  Finding delphi developers here is nearly impossible.  I only know of dev company using delphi and, for historical reasons, I can't use them. &lt;br /&gt;.net developers is a different story.  I could throw a stone out the window and hit one (seriously, they're just across the road).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Finally&lt;/span&gt;&lt;br /&gt;I am not abandoning delphi completely, I have a number of delphi apps to maintain so I will be using it for a while yet.   .net is not a silve bullet either.  For web apps I find .net better, but for desktop apps it's pretty much even.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-9154135841281475949?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/9154135841281475949/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=9154135841281475949' title='25 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/9154135841281475949'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/9154135841281475949'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2009/11/why-i-am-moving-from-delphi-to-net.html' title='Why I am moving from delphi to .net'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>25</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-4235925772316569032</id><published>2009-09-22T16:43:00.002+12:00</published><updated>2009-09-22T16:52:12.203+12:00</updated><title type='text'>D2010 suppport in tiOPF</title><content type='html'>tiOPF is a Object Persistence Framework. That is, it is a framework based around saving your objects to, and loading them from, databases and/or flat files.&lt;br /&gt;&lt;br /&gt;Delphi 2010 support has now been added to the latest repository version.&lt;br /&gt;&lt;br /&gt;No release has been made as of yet, so you need to to retrieve it from the subversion repository.  See &lt;a href="http://tiopf.sourceforge.net/SourceCodeRepository.shtml"&gt;here&lt;/a&gt; for instructions.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Notes&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Running unit tests requires copying the xdom.pas unit from Delphi 2009as this is no longer supplied&lt;br /&gt;&lt;/li&gt;&lt;li&gt;There are a large number of failures with BDE paradox tests.  I haven't  investigated this yetas no-one uses paradox any more&lt;br /&gt;&lt;/li&gt;&lt;li&gt;tiVirtualTree and related components have been removed from the gui  controls as they don't work under D2009/D2010. &lt;/li&gt;&lt;li&gt;Unicode is still not supported :(&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;Links&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://tiopf.sourceforge.net/"&gt;tiopf.com&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://tiopf.sourceforge.net/Doc/overview/index.shtml"&gt;tiopf overview&lt;/a&gt;&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/7028181408582795486-4235925772316569032?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/4235925772316569032/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=4235925772316569032' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/4235925772316569032'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/4235925772316569032'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2009/09/d2010-suppport-in-tiopf.html' title='D2010 suppport in tiOPF'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-2760353901953193940</id><published>2009-09-15T15:56:00.004+12:00</published><updated>2009-09-16T00:00:20.750+12:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MonoTouch'/><category scheme='http://www.blogger.com/atom/ns#' term='Mono'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><title type='text'>C# for the iPhone: Monotouch released</title><content type='html'>Novell's &lt;a href="http://monotouch.net/"&gt;MonoTouch&lt;/a&gt; product  has been released.  MonoTouch is mono for the iPhone.&lt;br /&gt;This allows compiling .net applications to native code and deploying to the iPhone.&lt;br /&gt;&lt;br /&gt;There are akready 200 apps in the app store using Mono via Unity so the underlying technology is fairly well tested.  MonoTouch adds Cocoa support and integration into MonoDevelop.&lt;br /&gt;&lt;br /&gt;MonoTouch has 2 main issues for some users, the $399US price point, and the logo.&lt;br /&gt;The price has disappointed a number of beta testers  and the logo is the second worst I have seen recently (worst is the &lt;a href="http://www.toastmasters.org.nz/index.cfm/Club_Finder.html"&gt;Toastmasters&lt;/a&gt; goatse).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-2760353901953193940?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/2760353901953193940/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=2760353901953193940' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/2760353901953193940'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/2760353901953193940'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2009/09/c-for-iphone-monotouch-released.html' title='C# for the iPhone: Monotouch released'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-9129973550293285710</id><published>2009-08-28T14:44:00.004+12:00</published><updated>2009-08-29T10:47:23.153+12:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='virtual machines'/><category scheme='http://www.blogger.com/atom/ns#' term='delphi'/><category scheme='http://www.blogger.com/atom/ns#' term='virtual box'/><category scheme='http://www.blogger.com/atom/ns#' term='vmware'/><title type='text'>When you install Delphi 2010, put it in a virtual machine</title><content type='html'>I recently compared the performance of virtual machines with the real hardware.  The figures were &lt;a href="http://sourceitsoftware.blogspot.com/2009/07/windows-performance-index-vmware.html"&gt;suprisingly good&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Shortly after that, disaster struck.  My laptop wouldn't turn on.  It took Dell 2 weeks to fix, replacing the motherboard and the video card.&lt;br /&gt;&lt;br /&gt;If I had delphi installed directly, I would have had 2 weeks of very limited productivity.  As it was, I ripped the hard drive out, stuck it in a usb caddy and continued working on another machine.  I was back up to speed the next day. &lt;br /&gt;&lt;span style="font-style: italic;"&gt;Edit: It didn't take a full day to get productive again, I did other work until it became apparent that it would be a while before my computer was fixed.  It only took about 30 minutes to transfer the data over and get going.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If it had been a hard drive problem, I would have restored the latest vm backup off a dvd, pulled the latest changes from the version control or the source backup and been back up to speed with limited data loss.&lt;br /&gt;&lt;br /&gt;I get a new laptop next month.  Installing delphi is going to be as easy as installing vmware and copying the vm files over.  30 minutes work, most of which is surfing the internet waiting for the files to copy.  The last time I actually had to install Delphi, it took hours.&lt;br /&gt;&lt;br /&gt;There are other advantages as well, my development backups fit on a single dual layer dvd, I get to run and test on multiple OSs and disaster recovery plan is much shorter.&lt;br /&gt;&lt;br /&gt;So make Delphi 2010 your starting point.  Download &lt;a href="http://www.virtualbox.org/"&gt;Virtual Box&lt;/a&gt;, &lt;a href="http://www.vmware.com/"&gt;VMWare Workstation ($$$)&lt;/a&gt; or &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=28C97D22-6EB8-4A09-A7F7-F6C7A1F000B5&amp;amp;displaylang=en"&gt;Virtual PC&lt;/a&gt; and use that for development.   If you are running Windows 7, you could look into Windows XP Mode and use that.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-9129973550293285710?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/9129973550293285710/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=9129973550293285710' title='13 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/9129973550293285710'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/9129973550293285710'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2009/08/when-you-install-delphi-2010-put-it-in.html' title='When you install Delphi 2010, put it in a virtual machine'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>13</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-2788674242971189368</id><published>2009-08-14T09:56:00.002+12:00</published><updated>2009-08-14T10:36:44.798+12:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='excel'/><title type='text'>Changing Excel query connection strings</title><content type='html'>We use Excel and database queries extensively for reporting purposes.  It's quick and easy to set-up, and provides reports that our clients can manipulate.&lt;br /&gt;&lt;br /&gt;However I have recently run into a rather painful excel quirk with ODBC connections: Excel stores the database connection string internally.  Even if you change the ODBC connection on the computer, excel still uses the original connection from when the query was created.&lt;br /&gt;&lt;br /&gt;This bit us when moving the reports to a different machine.  Despite having the same ODBC connection set up, excel wouldn't refresh the query and gave the error "[Microsoft][ODBC SQL Server Driver][TCP/IP Sockets]SQL Server does not exist or access denied."&lt;br /&gt;&lt;br /&gt;Aside&lt;br /&gt;A similar problem can happen if you update the database from sql server 2000 to sql server 2005 or 2008.  In that case you may get the error  "[Microsoft][SQL Native Client][SQL Server]User 'DOMAIN\username' does not have permission to run DBCC TRACEON."  In that case, you need to alter the connection string to change "APP=Microsoft® Query" to something else.  Apparently MS hard coded a check for "Microsoft® Query" in sql server which then runs DBCC TRACEON for no apparent reason.  I suggest  "APP=WTFWYT"&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Changing one query&lt;/span&gt;&lt;br /&gt;(from &lt;a href="http://social.msdn.microsoft.com/forums/en-US/sqldataaccess/thread/ad8ad177-65b3-4962-b0aa-530a2c9d6d86"&gt;here&lt;/a&gt;)&lt;br /&gt;"&lt;span style="font-style: italic;"&gt;Open the worksheet and place the cursor on a cell within the cell range of &lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;the query.  Press Alt-F11 to open the VBEditor.  Press Ctrl-G to open the &lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Intermediate window.  Type the command:  ? ActiveCell.QueryTable.Connection.   &lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;The embedded connection string will be echoed back to the screen.  Put double &lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;quotes around the string and update the connection information with the new &lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;server info.  Move the cursor to the beginning of the connection string and &lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;insert the following in front of the string:   &lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;ActiveCell.QueryTable.Connection =&lt;/span&gt;&lt;br /&gt;"&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Changing multiple queries in a spreadsheet&lt;/span&gt;&lt;br /&gt;(modified from &lt;a href="http://social.msdn.microsoft.com/Forums/en-US/sqlanalysisservices/thread/a013c536-164e-4883-b989-93e9e33d8664"&gt;here&lt;/a&gt;)&lt;br /&gt;You need to create the following macro (change connection string to suit, see above) and run it in each spreadsheet requiring change.  (See the steps below). Once the macro has run successfully, delete it before saving the spreadsheet.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Sub ChangeConnections()&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;     Dim sh As Worksheet, qy As QueryTable  &lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;     For Each ws In ActiveWorkbook.Sheets&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;       For Each qy In ws.QueryTables&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;            qy.Connection = "..."&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;            On Error Resume Next&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;            qy.Refresh&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;            If Err.Number &lt;&gt; 0 Then MsgBox "Problem refreshing QueryTable: " &amp;amp; Err.Description&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;       Next qy&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;    Next ws&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;End Sub&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Getting the new connection string&lt;/span&gt;&lt;br /&gt;The easiest way to find the new connections string is to create a new query and do the ?ActiveCell.QueryTable.Connection trick.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-2788674242971189368?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/2788674242971189368/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=2788674242971189368' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/2788674242971189368'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/2788674242971189368'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2009/08/changing-excel-query-connection-strings.html' title='Changing Excel query connection strings'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-7044704333267190276</id><published>2009-07-10T16:44:00.004+12:00</published><updated>2009-07-15T12:02:48.565+12:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='virtual machines'/><category scheme='http://www.blogger.com/atom/ns#' term='virtual box'/><category scheme='http://www.blogger.com/atom/ns#' term='vmware'/><title type='text'>Windows Performance Index - VMware workstation v Virtual Box</title><content type='html'>&lt;a href="http://www.virtualbox.org/"&gt;Virtual Box 3&lt;/a&gt; has been released.  I haven't used previous versions of VB, but it has a good rep. Version 3 now supports 3d acceleration.  I have been wanting to use Aero and Glass in  my virtual machines so that I could develop Vista specific applications so I gave it a try.&lt;br /&gt;&lt;br /&gt;First the bad news, VB doesn't support enough 3d features to run Aero (neither does VMware).  I did discover a work around though, connect to your virtual machine using Remote Desktop Connection from a Vista machine, turn all graphics options to high and volia.&lt;br /&gt;&lt;br /&gt;While I had VB installed, I did a quick and dirty comparision with VMware workstation using Windows Performance Index. Take these results with a grain of salt, I didn't spend much time playing with the setup and tweaking.  I couldn't get dual core to work on VB, it just blue-screened, and I didn't have the time to spend sorting it out.&lt;br /&gt;&lt;br /&gt;Windows Performance Index&lt;br /&gt;&lt;table style="border-collapse: collapse; width: 527pt;" border="0" cellpadding="0" cellspacing="0" width="702"&gt;&lt;col style="width: 111pt;" width="148"&gt;  &lt;col style="width: 101pt;" width="134"&gt;  &lt;col style="width: 93pt;" width="124"&gt;  &lt;col style="width: 111pt;" span="2" width="148"&gt;  &lt;tbody&gt;&lt;tr style="height: 15pt;" height="20"&gt;   &lt;td class="xl65" style="height: 15pt; width: 111pt; font-weight: bold;" height="20" width="148"&gt;&lt;br /&gt;&lt;/td&gt;   &lt;td class="xl68" style="width: 101pt; text-align: center; font-weight: bold;" width="134"&gt;Host&lt;/td&gt;   &lt;td class="xl68" style="width: 93pt; text-align: center; font-weight: bold;" width="124"&gt;VMware&lt;br /&gt;Single proc&lt;/td&gt;   &lt;td class="xl68" style="width: 111pt; text-align: center; font-weight: bold;" width="148"&gt;VMware&lt;br /&gt;Dual proc&lt;/td&gt;   &lt;td class="xl69" style="width: 111pt; text-align: center; font-weight: bold;" width="148"&gt;Virtual Box&lt;br /&gt;Single Proc&lt;/td&gt;  &lt;/tr&gt;  &lt;tr style="height: 15pt;" height="20"&gt;   &lt;td class="xl66" style="height: 15pt; font-weight: bold;" height="20"&gt;Processor&lt;/td&gt;   &lt;td style="text-align: center;" class="xl70"&gt;5.4&lt;/td&gt;   &lt;td style="text-align: center;" class="xl70"&gt;4.4&lt;/td&gt;   &lt;td style="text-align: center;" class="xl70"&gt;5.2&lt;/td&gt;   &lt;td style="text-align: center;" class="xl71"&gt;4.4&lt;/td&gt;  &lt;/tr&gt;  &lt;tr style="height: 15pt;" height="20"&gt;   &lt;td class="xl66" style="height: 15pt; font-weight: bold;" height="20"&gt;Memory&lt;/td&gt;   &lt;td style="text-align: center;" class="xl70"&gt;5.1&lt;/td&gt;   &lt;td style="text-align: center;" class="xl70"&gt;4.9&lt;/td&gt;   &lt;td style="text-align: center;" class="xl70"&gt;5.2&lt;/td&gt;   &lt;td style="text-align: center;" class="xl71"&gt;5.9&lt;/td&gt;  &lt;/tr&gt;  &lt;tr style="height: 15pt;" height="20"&gt;   &lt;td class="xl67" style="height: 15pt; font-weight: bold;" height="20"&gt;Primary Hard disk&lt;/td&gt;   &lt;td style="text-align: center;" class="xl72"&gt;5.4&lt;/td&gt;   &lt;td style="text-align: center;" class="xl72"&gt;5.3&lt;/td&gt;   &lt;td style="text-align: center;" class="xl72"&gt;5.4&lt;/td&gt;   &lt;td style="text-align: center;" class="xl73"&gt;4.7&lt;/td&gt;  &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;The memory figures are surprising, I am not sure if the VB figures of 5.9 are real or just a sign of something wrong somewhere.  Draw your own conclusions on that. &lt;br /&gt;&lt;br /&gt;VB is slower in hard drive, but otherwise up with the play processor wise.  Getting dual core working would probably give similar processor figures to VMware dual core.&lt;br /&gt;&lt;br /&gt;I was impressed with how well VMware matches up to the host system.  While VB doesn't seem to be quite there yet, it is still doing pretty well, and you can't beat the price.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-7044704333267190276?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/7044704333267190276/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=7044704333267190276' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/7044704333267190276'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/7044704333267190276'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2009/07/windows-performance-index-vmware.html' title='Windows Performance Index - VMware workstation v Virtual Box'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-4445880239341127148</id><published>2009-06-30T22:42:00.005+12:00</published><updated>2009-07-01T07:51:42.981+12:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iphone development'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><category scheme='http://www.blogger.com/atom/ns#' term='Mono'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><title type='text'>iPhone programming might be getting a whole lot easier</title><content type='html'>The mono project has announced &lt;a href="http://www.mono-project.com/MonoTouch"&gt;MonoTouch&lt;/a&gt;.   MonoTouch is Mono for the iPhone and the iPod touch.   Applications writen with MonoTouch work and non-jailbroken phones, and can be submitted to the app store.&lt;br /&gt;&lt;br /&gt;See &lt;a href="http://tirania.org/blog/archive/2009/Jun-29.html"&gt;Miguel's blog&lt;/a&gt; for additional details.  According to the comments, a beta should be released in August.&lt;br /&gt;&lt;br /&gt;Time to start brushing up my C# skills.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-4445880239341127148?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/4445880239341127148/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=4445880239341127148' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/4445880239341127148'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/4445880239341127148'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2009/06/iphone-programming-might-be-getting.html' title='iPhone programming might be getting a whole lot easier'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-1834218765419791531</id><published>2009-06-29T18:06:00.005+12:00</published><updated>2009-06-30T22:49:02.311+12:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Guido just doesn't get windows programming</title><content type='html'>Among the blogs I follow is that of &lt;a href="http://neopythonic.blogspot.com/"&gt;Guido van Rossum&lt;/a&gt;, the creator of Python.  Mostly they are interesting but his latest one (&lt;a href="http://neopythonic.blogspot.com/2009/06/ironpython-in-action-and-decline-of.html"&gt;IronPython in Action and the Decline of Windows&lt;/a&gt;) is a large pile of wtf.  Apparently programming windows apps is tedious and gui creation requires many lines of code.  Even more surprising to me, web apps are far easier to create.&lt;br /&gt;&lt;br /&gt;Wow, apparently he has never heard of delphi, visual studio or any of the other gui editors that have been about since at least the mid 80s.  The last time I laid a gui out in code, other than for eductational purposes, would have been about 1986.  I have no desire to do it again either.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-1834218765419791531?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/1834218765419791531/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=1834218765419791531' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/1834218765419791531'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/1834218765419791531'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2009/06/guido-just-doesnt-get-windows.html' title='Guido just doesn&apos;t get windows programming'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-3765983508947641971</id><published>2009-05-13T15:41:00.003+12:00</published><updated>2009-05-13T16:46:01.222+12:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iphone development'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><title type='text'>iPhone Dev: Zombie Mansion post mortem</title><content type='html'>&lt;span style="font-weight: bold;"&gt;Overview&lt;/span&gt;&lt;br /&gt;I released Zombie Mansion in mid December 08.  It is a 1st person shooter, the 2nd available on the iPhone and the first one to be designed for mobile devices rather than being a pc port.  ZM was a port and extension of the work I had done previously on the &lt;a href="http://sourceitsoftware.com/yeti.html"&gt;Yeti engine&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Seeing as how every other iPhone developer is sharing their tales of mega success, or crushing failure, I though I would add my story.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Sales&lt;/span&gt;&lt;br /&gt;ZM has sold steadily, if not spectacularly.   Unfortunately I have not made enough to pay off my house and buy a fast car.  On the other hand, it sold well enough to pay my mortgage payments for the 1st 3 months.  Sales are as you would expect: hundreds sold in the first couple of days, rapidly dropping off as ZM moved off the recent releases page.  My first update provided a brief blip but my second update was unnoticeable in terms of sales.&lt;br /&gt;&lt;br /&gt;I took 2 weeks leave to finish ZM, and I estimate that I spent the equivalent of another 2 weeks previously.  This doesn't include the original porting work I did moving the yeti engine to the pocket pc.&lt;br /&gt;&lt;br /&gt;As a return on time spent, ZM performed slightly better than working at my day job.  It was however considerably more fun.  It would have performed even better but I made a couple of bad design decisions.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Programming&lt;/span&gt;&lt;br /&gt;Unusually, I did the bulk of the development in windows using visual studio rather than in xcode on OSX.  I already had an OpenGL ES port running on Windows Mobile and Windows so an iPhone port wasn't much of a problem.&lt;br /&gt;&lt;br /&gt;Coding was done in a mixture of C (yeti code) and C++ (my code).&lt;br /&gt;On the iPhone, I used the &lt;a href="http://oolongengine.com/"&gt;Oolong engine&lt;/a&gt; to handle the sound, input and 3d setup.  Oolong provides c++ wrapper classes for all this (and more).&lt;br /&gt;&lt;br /&gt;On the pc and windows mobile side, I used the &lt;a href="http://www.imgtec.com/powervr/insider/powervr-sdk.asp"&gt;PowerVr sdk&lt;/a&gt; to handle 3d setup.  Keyboard handling is trivial, and I used &lt;a href="http://www.shlzero.com/"&gt;Hekkus&lt;/a&gt; to provide sound support.&lt;br /&gt;&lt;br /&gt;Once I had this all set-up,I did most coding in visual studio.  At irregular intervals, I would reboot into OSX and compile with xcode.  I mostly used xcode for iPhone specific stuff and performance testing.  All my support tools (map editor, 3d importer etc.) are windows based (in c++ builder and Delphi) so that necessitated mostly using windows.  I prefer visual studio to xcode, so it wasn't much of a chore.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Mistakes&lt;/span&gt;&lt;br /&gt;I made a couple of mistakes.  The first, and most major was simplifying the weapons too much.  I went with one weapon, a staff, with upgrades rather than with multiple weapons.  In retrospect, a bad call.&lt;br /&gt;&lt;br /&gt;The second mistake was not putting some help tips around controls.  The controls work well if you leave your thumb on the d pad and slide it to control.  If you pick your thumb up and move it, the controls don't work as well.  Some easy way of explaining this to the player would have made their initial impressions better.&lt;br /&gt;&lt;br /&gt;The underlying problem is that perennial development favourite, I underestimated the time needed to write the software.  I ran out of annual leave and thus ran out of time.  While I enjoyed the game that I wrote, it would have been better if I had more time to add extra features and polish.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Dealing with Apple&lt;/span&gt;&lt;br /&gt;There are 3 major drawbacks to iPhone development: Apple, Apple and Apple.  I don't know if they are overworked, incompetent or just don't care.  Either way, developer support seems to be missing in action.&lt;br /&gt;&lt;br /&gt;Since I have had children, I have made a concious effort to improve my language, removing the more robust terms I picked up working in the abbottiors.   Three months of dealing with Apple has made a mockery of my self-betterment attempts, leaving me swearing like Gordon Ramsey on a bad day.&lt;br /&gt;&lt;br /&gt;Simply getting a paid developer contract took six weeks.  My first payment, for December, didn't get paid until late March.  Emails asking when money was going to arrive were ignored, or fobbed off with stock responses or outright lies.  Whenever I phoned, I was told they couldn't help and to email another department.&lt;br /&gt;&lt;br /&gt;Even when I did get paid, there was no notification.  Apple can email me every week, trying to sell me a second rate album farted out by a talentless boy band, but they can't be bothered sending me an email saying "We have now condescended to pay you".&lt;br /&gt;&lt;br /&gt;As a comparison, RegNow emailed me on Jan 4th letting me know my December payment had been released, and the money was in my account on Jan 6th.  Even now that Apple has decided to make my monthly payments on a monthly basis, they still take nearly 40 days longer than Regnow.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Random thoughts&lt;/span&gt;&lt;br /&gt;There is clearly still money to be made in iPhone dev.  ZM hasn't disturbed the sales charts, but it has still sold well enough to cover it's costs and my time.  I imagine that there are many developers in a similar position, not making riches, but making enough to get by and keep developing.   A small stable of good games/applications could provide a nice living without requiring a hit.&lt;br /&gt;&lt;br /&gt;It used to be that you could get a large amount of exposure and thus sales by releasing an update every couple of weeks.  However the volume of new applications has changed that.  There are so many apps being released each day that the initial rush of sales from being in the "what's new" charts is much smaller.  You need to get sales the hard way, with marketing; promotion and advertising.&lt;br /&gt;&lt;br /&gt;I also have a couple of windows shareware applications, Pics Print and Rental Property Manager.  While it is not easy to compare windows utilities and business applications with an iPhone, the return on time invested is far greater for these 2, particularly RPM, than for ZM.&lt;br /&gt;&lt;br /&gt;All this brings me full circle from where I started out six months ago.  There is money to be made in iPhone apps, but there is also money to be made in windows shareware as well.  If you are a windows developer, particularly if you are a Delphi developer, then you are probably better off developing windows shareware than iPhone apps. I know a lot more developers making money off windows than off iPhones.&lt;br /&gt;&lt;br /&gt;Oh, and &lt;a href="http://sourceitsoftware.blogspot.com/2008/08/programming-for-iphone-really-sucks.html"&gt;developing for iPhones still sucks&lt;/a&gt;!  Not as badly as I first thought, but still noticeably.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-3765983508947641971?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/3765983508947641971/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=3765983508947641971' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/3765983508947641971'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/3765983508947641971'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2009/05/iphone-dev-zombie-mansion-post-mortem.html' title='iPhone Dev: Zombie Mansion post mortem'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-6670334488267801199</id><published>2009-04-17T20:39:00.006+12:00</published><updated>2009-04-22T18:54:05.964+12:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='delphi'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>And Now for Something Completely Different</title><content type='html'>One of the pragmatic programmer tenets is to learn a new programming language every year.  I'm a bit behind on that, I haven't learn a new language since 2002 (I don't count objective C because I hate it and have only learnt the bare minimum necessary to get by).  Unfortunately the need to earn a living has gotten in the way of random learning.&lt;br /&gt;&lt;br /&gt;However I have now been programming in Delphi for 15 years.  It's starting to get a bit boring and it's time to kick-start the brain again.  While Delphi will be my main language for the near future, I am going to make the effort to learn something different.&lt;br /&gt;&lt;br /&gt;The main things I am looking for in my language de jour are&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Dynamically typed (I have done statically typed languages for decades)&lt;/li&gt;&lt;li&gt;Popular (general rule of thumb, should be at least as popular as delphi)&lt;/li&gt;&lt;li&gt;Object Orientated&lt;/li&gt;&lt;li&gt;Cross platform&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Batteries included&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;This pretty much narrows it down to Perl, Php, Python and Ruby.  I was initially tempted by Ruby as I don't yet have an R on my alphabetical list of programming languages.   However I have settled on Python instead.&lt;br /&gt;&lt;br /&gt;Part of the reason for going with Python is the presence of the            &lt;a href="http://code.google.com/p/python4delphi/"&gt;Python for Delphi&lt;/a&gt; components.  These promise to let you use python as a scripting language inside delphi apps.  These components are used in the &lt;a href="http://code.google.com/p/pyscripter/"&gt;PyScripter&lt;/a&gt; ide.&lt;br /&gt;&lt;br /&gt;The easiest way I have found to get started is to use &lt;a href="http://www.portablepython.com/"&gt;Portable Python&lt;/a&gt;.  This will put Python and a few tools (inc. PyScripter) into a portable drive along with a few tools and useful modules such as &lt;a href="http://www.djangoproject.com/"&gt;Django&lt;/a&gt;. This is considerably easier for a python newbie than sourcing and installing the packages separately.&lt;br /&gt;&lt;br /&gt;Some useful links to get started with:&lt;br /&gt;&lt;a href="http://python.org/"&gt;Official website&lt;/a&gt;&lt;br /&gt;&lt;a href="http://docs.python.org/tutorial/"&gt;Official python tutorial (v2.6)&lt;/a&gt;&lt;br /&gt;&lt;a href="http://diveintopython.org/index.html"&gt;Dive onto python online book&lt;/a&gt; (useful but a bit old)&lt;br /&gt;&lt;a href="http://pycon.blip.tv/"&gt;Pycon US 2009 videos&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.reddit.com/r/Python/"&gt;Reddit python feed&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-6670334488267801199?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/6670334488267801199/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=6670334488267801199' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/6670334488267801199'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/6670334488267801199'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2009/04/and-now-for-something-completely.html' title='And Now for Something Completely Different'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-4950394657314321948</id><published>2009-03-09T12:52:00.009+13:00</published><updated>2009-03-17T15:16:05.983+13:00</updated><title type='text'>Filtering generic collections with anonymous methods</title><content type='html'>I have recently been adding generics to the ti Object Persistence Framework. As part of that I was asked to add enumerator filtering.  I did this using a similar technique to that shown &lt;a href="http://www.malcolmgroves.com/blog/?p=273"&gt;here&lt;/a&gt; by Malcolm Groves.&lt;br /&gt;&lt;br /&gt;I ended up with code used like this:&lt;br /&gt;&lt;pre class="sourcecode"&gt;&lt;code&gt;&lt;br /&gt;&lt;b&gt;for&lt;/b&gt; item &lt;b&gt;in&lt;/b&gt; Flist.FilteredEnumerator(&lt;b&gt;function&lt;/b&gt; (TestObject: TtiOPFTestIntegerProp): Boolean&lt;br /&gt;                                &lt;b&gt;begin&lt;/b&gt;&lt;br /&gt;                                  result:= TestObject.IntField &lt;b&gt;mod&lt;/b&gt; 2 = 1;&lt;br /&gt;                                &lt;b&gt;end&lt;/b&gt;) &lt;b&gt;do&lt;/b&gt;&lt;br /&gt;&lt;b&gt;begin&lt;/b&gt;&lt;br /&gt; inc(intCount);&lt;br /&gt; intSum:= intSum + item.IntField;&lt;br /&gt;&lt;b&gt;end&lt;/b&gt;;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I was happy enough with the result, but I wasn't happy with the implementation.  I wanted something that was, well, more generic.  What I ended up doing was wrapping the existing enumerator into one containing a filter.  This will work with any generic collection that descends from TEnumerable&lt;t&gt;.  I.e. TList&lt;t&gt;, TQueue&lt;t&gt;, TStack&lt;t&gt;, TDictionary&lt;t&gt; and the TObjectXXX&lt;t&gt; variations&lt;br /&gt;&lt;br /&gt;To implement an enumerator, a class must have a GetEnumerator function.  This returns an object (or a record) that has the Current property and the MoveNext function.  Delphi does a fair amount of work behind the scenes to wrap this all up nicely.  See The Delphi Geek's series on enumerators &lt;a href="http://17slon.com/blogs/gabr/2007/03/fun-with-enumerators.html"&gt;here&lt;/a&gt; for more background.&lt;br /&gt;&lt;br /&gt;Wrapping an existing enumerator meant I could use the existing GetCurrent and MoveNext for accessing the collection.  Filtering then becomes as simple as:&lt;br /&gt;&lt;br /&gt;&lt;pre class="sourcecode"&gt;&lt;code&gt;&lt;b&gt;function&lt;/b&gt; TFilteredEnumerator&amp;lt;T&amp;gt;.MoveNext: Boolean;&lt;br /&gt;&lt;b&gt;begin&lt;/b&gt;&lt;br /&gt;&lt;b&gt;  while&lt;/b&gt;  FEnumerator.MoveNext &lt;b&gt;do&lt;/b&gt;&lt;br /&gt;&lt;b&gt;  begin&lt;/b&gt;&lt;br /&gt;&lt;b&gt;    if&lt;/b&gt; FPredicate(FEnumerator.Current) &lt;b&gt;then&lt;/b&gt;&lt;br /&gt;     exit(true);&lt;br /&gt;&lt;b&gt;  end&lt;/b&gt;;&lt;br /&gt; result:= false;&lt;br /&gt;&lt;b&gt;end&lt;/b&gt;;&lt;/code&gt;&lt;/pre&gt;The full code is as follows:&lt;br /&gt;&lt;pre class="sourcecode"&gt;&lt;span id="LabelHighlight"&gt;&lt;pre class="sourcecode"&gt;&lt;code class="keyword"&gt;unit&lt;/code&gt; FilteredEnumeratorU;&lt;br /&gt;&lt;br /&gt;&lt;code class="keyword"&gt;interface&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code class="keyword"&gt;uses&lt;/code&gt; Sysutils, generics.collections;&lt;br /&gt;&lt;br /&gt;&lt;code class="keyword"&gt;type&lt;/code&gt;&lt;br /&gt; TFilteredEnumerator&lt;t&gt; = &lt;code class="keyword"&gt;class&lt;/code&gt;&lt;br /&gt;&lt;code class="keyword"&gt;  private&lt;/code&gt;&lt;br /&gt;   FEnumerator: TEnumerator&lt;t&gt;;&lt;br /&gt;   FPredicate: TPredicate&lt;t&gt;;&lt;br /&gt;&lt;code class="keyword"&gt;  protected&lt;/code&gt;&lt;br /&gt;&lt;code class="keyword"&gt;    function&lt;/code&gt; DoGetCurrent: T;&lt;br /&gt;&lt;code class="keyword"&gt;  public&lt;/code&gt;&lt;br /&gt;&lt;code class="keyword"&gt;    constructor&lt;/code&gt; Create(AEnumerable: TEnumerable&lt;t&gt;; APredicate: TPredicate&lt;t&gt;);&lt;br /&gt;&lt;code class="keyword"&gt;    destructor&lt;/code&gt;  Destroy;&lt;br /&gt;&lt;code class="keyword"&gt;    function&lt;/code&gt; GetEnumerator: TFilteredEnumerator&lt;t&gt;;&lt;br /&gt;&lt;code class="keyword"&gt;    property&lt;/code&gt; Current: T &lt;code class="keyword"&gt;read&lt;/code&gt; DoGetCurrent;&lt;br /&gt;&lt;code class="keyword"&gt;    function&lt;/code&gt; MoveNext: Boolean;&lt;br /&gt;&lt;code class="keyword"&gt;  end&lt;/code&gt;;&lt;br /&gt;&lt;br /&gt;&lt;code class="keyword"&gt;implementation&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code class="comment"&gt;{ TFilteredEnumerator&lt;t&gt; }&lt;/t&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code class="keyword"&gt;constructor&lt;/code&gt; TFilteredEnumerator&lt;t&gt;.Create(AEnumerable: TEnumerable&lt;t&gt;; APredicate: TPredicate&lt;t&gt;);&lt;br /&gt;&lt;code class="keyword"&gt;begin&lt;/code&gt;&lt;br /&gt;&lt;code class="keyword"&gt;  inherited&lt;/code&gt; create;&lt;br /&gt; FEnumerator:= AEnumerable.GetEnumerator;&lt;br /&gt; FPredicate:= APredicate;&lt;br /&gt;&lt;code class="keyword"&gt;end&lt;/code&gt;;&lt;br /&gt;&lt;br /&gt;&lt;code class="keyword"&gt;destructor&lt;/code&gt; TFilteredEnumerator&lt;t&gt;.Destroy;&lt;br /&gt;&lt;code class="keyword"&gt;begin&lt;/code&gt;&lt;br /&gt; FEnumerator.Free;&lt;br /&gt;&lt;code class="keyword"&gt;  inherited&lt;/code&gt; Destroy;&lt;br /&gt;&lt;code class="keyword"&gt;end&lt;/code&gt;;&lt;br /&gt;&lt;br /&gt;&lt;code class="keyword"&gt;function&lt;/code&gt; TFilteredEnumerator&lt;t&gt;.DoGetCurrent: T;&lt;br /&gt;&lt;code class="keyword"&gt;begin&lt;/code&gt;&lt;br /&gt; result:= FEnumerator.Current;&lt;br /&gt;&lt;code class="keyword"&gt;end&lt;/code&gt;;&lt;br /&gt;&lt;br /&gt;&lt;code class="keyword"&gt;function&lt;/code&gt; TFilteredEnumerator&lt;t&gt;.GetEnumerator: TFilteredEnumerator&lt;t&gt;;&lt;br /&gt;&lt;code class="keyword"&gt;begin&lt;/code&gt;&lt;br /&gt; result:= self;&lt;br /&gt;&lt;code class="keyword"&gt;end&lt;/code&gt;;&lt;br /&gt;&lt;br /&gt;&lt;code class="keyword"&gt;function&lt;/code&gt; TFilteredEnumerator&lt;t&gt;.MoveNext: Boolean;&lt;br /&gt;&lt;code class="keyword"&gt;begin&lt;/code&gt;&lt;br /&gt;&lt;code class="keyword"&gt;  while&lt;/code&gt;  FEnumerator.MoveNext &lt;code class="keyword"&gt;do&lt;/code&gt;&lt;br /&gt;&lt;code class="keyword"&gt;  begin&lt;/code&gt;&lt;br /&gt;&lt;code class="keyword"&gt;    if&lt;/code&gt; FPredicate(FEnumerator.Current) &lt;code class="keyword"&gt;then&lt;/code&gt;&lt;br /&gt;     exit(true);&lt;br /&gt;&lt;code class="keyword"&gt;  end&lt;/code&gt;;&lt;br /&gt; result:= false;&lt;br /&gt;&lt;code class="keyword"&gt;end&lt;/code&gt;;&lt;br /&gt;&lt;br /&gt;&lt;code class="keyword"&gt;end&lt;/code&gt;.&lt;br /&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/pre&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;To use filtering in action, simply do something like:&lt;br /&gt;&lt;br /&gt;&lt;pre class="sourcecode"&gt;&lt;br /&gt;&lt;code class="keyword"&gt;for&lt;/code&gt; xxx &lt;code class="keyword"&gt;in&lt;/code&gt; TFilteredEnumerator&amp;lt;T&amp;gt;.Create(queue, &lt;code class="keyword"&gt;function&lt;/code&gt; (Arg1: T): Boolean&lt;br /&gt;                                                        &lt;code class="keyword"&gt;begin&lt;/code&gt;&lt;br /&gt;                                                          result:= ...;&lt;br /&gt;                                                        &lt;code class="keyword"&gt;end&lt;/code&gt;)&lt;br /&gt;&lt;code class="keyword"&gt;do&lt;/code&gt;&lt;br /&gt;  ...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;eg&lt;br /&gt;&lt;br /&gt;&lt;pre class="sourcecode"&gt;&lt;br /&gt;&lt;code class="keyword"&gt;var&lt;/code&gt;&lt;br /&gt; queue: TQueue&amp;lt;&lt;code class="keyword"&gt;string&lt;/code&gt;&amp;gt;;&lt;br /&gt; cur, combined: &lt;code class="keyword"&gt;string&lt;/code&gt;;&lt;br /&gt; filter: TFilteredEnumerator&amp;lt;TTestObject&amp;gt;;&lt;br /&gt;&lt;code class="keyword"&gt;begin&lt;/code&gt;&lt;br /&gt; queue:= TQueue&amp;lt;&lt;code class="keyword"&gt;string&lt;/code&gt;&amp;gt;.Create;&lt;br /&gt;&lt;code class="keyword"&gt;  try&lt;/code&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;   &lt;code class="keyword"&gt;for&lt;/code&gt; cur &lt;code class="keyword"&gt;in&lt;/code&gt; TFilteredEnumerator&amp;lt;&lt;code class="keyword"&gt;string&lt;/code&gt;&amp;gt;.Create(queue, &lt;code class="keyword"&gt;function&lt;/code&gt; (Arg1: &lt;code class="keyword"&gt;string&lt;/code&gt;): Boolean&lt;br /&gt;                                                         &lt;code class="keyword"&gt;begin&lt;/code&gt;&lt;br /&gt;                                                           result:= Arg1 &amp;lt; &lt;code class="quote"&gt;'A'&lt;/code&gt;;&lt;br /&gt;                                                         &lt;code class="keyword"&gt;end&lt;/code&gt;)&lt;br /&gt;   &lt;code class="keyword"&gt;do&lt;/code&gt;&lt;br /&gt;   &lt;code class="keyword"&gt;begin&lt;/code&gt;&lt;br /&gt;     combined:= combined + cur;&lt;br /&gt;   &lt;code class="keyword"&gt;end&lt;/code&gt;;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;If you are deriving from a collection, you could also wrap this into a method:&lt;br /&gt;&lt;br /&gt;&lt;pre class="sourcecode"&gt;&lt;code&gt;&lt;br /&gt;&lt;b&gt;function&lt;/b&gt; TFilterableList.Filter(APredicate: TPredicate&amp;lt;ttestobject&amp;gt;): TFilteredEnumerator&amp;lt;ttestobject&amp;gt;;&lt;br /&gt;&lt;b&gt;begin&lt;/b&gt;&lt;br /&gt; result:= TFilteredEnumerator&amp;lt;ttestobject&amp;gt;.Create(self, APredicate);&lt;br /&gt;&lt;b&gt;end&lt;/b&gt;;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Source can be downloaded from &lt;a href="http://www.sourceitsoftware.com/download/FilteredEnumerator.zip"&gt;here&lt;/a&gt;.&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-4950394657314321948?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/4950394657314321948/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=4950394657314321948' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/4950394657314321948'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/4950394657314321948'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2009/03/filtering-generic-collections-with.html' title='Filtering generic collections with anonymous methods'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-156011914271699070</id><published>2009-02-10T13:18:00.001+13:00</published><updated>2009-02-10T13:21:04.528+13:00</updated><title type='text'>Microsoft Study: TDD reduced defects by 40%-90%, increased dev time by 15% - 35%</title><content type='html'>Found via Reddit.&lt;br /&gt;&lt;br /&gt;See &lt;a href="http://research.microsoft.com/en-us/projects/esm/nagappan_tdd.pdf"&gt;here&lt;/a&gt; (pdf).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-156011914271699070?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/156011914271699070/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=156011914271699070' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/156011914271699070'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/156011914271699070'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2009/02/microsoft-study-tdd-reduced-defects-by.html' title='Microsoft Study: TDD reduced defects by 40%-90%, increased dev time by 15% - 35%'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-6022299214459176494</id><published>2009-01-19T10:02:00.004+13:00</published><updated>2009-01-19T13:08:29.818+13:00</updated><title type='text'>Garbage collection - it's not about lazyness</title><content type='html'>There seems to be a common belief amongst a number of Delphi programmers (and c++ programmers etc) that garbage collection is all about being too lazy to do your own clean-up.&lt;br /&gt;&lt;br /&gt;E.g. Babnik asks "&lt;a href="http://thedorictemple.blogspot.com/2009/01/what-is-it-about-garbage-collection.html"&gt;What is it about Garbage Collection?&lt;/a&gt;" (kudos for actually asking the question) and his post has the implicit assumption that advocates are trying to avoid doing a bit of minor work.&lt;br /&gt;&lt;br /&gt;Others have posted far more stronger comments (check the responses to Babnik's post) straight out stating that gc = lazyness, bad coding and a slack attitude to life.  I find this attitude condescending and offensive.  The reason I want gc, is not because I write bad code, but because i want to write better code.&lt;br /&gt;&lt;br /&gt;I would like to see garbage collection in native Delphi, not as a mandatory feature, but as an option.  It's not something I am holding my breath for, but if there was one thing I could add, that would be it.&lt;br /&gt;&lt;br /&gt;I know I am repeating myself, but here are my main reasons for wanting a gc (expanded from an earlier &lt;a href="http://sourceitsoftware.blogspot.com/2008/01/garbage-collection-in-delphi-win-32-why.html"&gt;post&lt;/a&gt; on the subject):&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Better code: In a non gc language, you end up with a number of idioms and practices to guard against memory leaks. Delphi has several of these.&lt;br /&gt;E.g.:&lt;br /&gt;It is rare to return an object from a function. Typically you would create an object and then pass it to a procedure to be modified.&lt;br /&gt;The use of assign rather than :=&lt;br /&gt;The use of Owner, Owned and the like to solve object destruction problems)&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Less code: I performed a naive analysis on my most recent project by removing most .Free calls and the supporting destructors and try … finally blocks. The result was about 4% fewer lines of code.  More importantly, the code I removed was boring, boilerplate which solved no business problems and added no value (other than preventing leaks)&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Faster development:  There are some minor time savings to be had simply by typing less code.  However when I was regularly programming in c# I found my productivity improved due to the change of coding style that gc allowed.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Fewer memory leaks: By reducing the need for manually freeing memory, a gc significantly reduces the scope for memory leaks. It is still possible to leak memory, but much harder.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;There are some problems that it is difficult to solve without a GC.   Linq is often given as an example.  Class operators (as opposed to record operators) is another&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;One of the main reasons I see for Delphi to have a gc, is that it's competitors have it.  If we are to persuade people to write applications in Delphi as opposed to C#, Java etc then requiring manual memory is at best a speed bump.&lt;br /&gt;&lt;br /&gt;Finally garbage collection definitely falls into the "Your kilometreage may vary" category.  If you are working in memory constrained environments then manual management is the way to go.  If you are writing database driven business apps or web apps (as I usually am) then manual management offers little or no advantage over a garbage collector.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-6022299214459176494?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/6022299214459176494/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=6022299214459176494' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/6022299214459176494'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/6022299214459176494'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2009/01/garbage-collection-its-not-about.html' title='Garbage collection - it&apos;s not about lazyness'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-5531134793739310080</id><published>2008-12-12T08:21:00.002+13:00</published><updated>2008-12-12T08:33:37.815+13:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><title type='text'>Zombie Mansion released for the iPhone</title><content type='html'>Zombie Mansion is  first person shooter game I have been developing for the past few months (and the cause of my receding hairline).  It got finally got approved yesterday.&lt;br /&gt;&lt;br /&gt;See &lt;a href="http://www.sourceitsoftware.com/zombie.html"&gt;here&lt;/a&gt; for screenshots and more info.&lt;br /&gt;See &lt;a href="http://toucharcade.com/link/http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=297779095&amp;amp;mt=8"&gt;here&lt;/a&gt; for the App store page.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-5531134793739310080?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/5531134793739310080/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=5531134793739310080' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/5531134793739310080'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/5531134793739310080'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2008/12/zombie-mansion-released-for-iphone.html' title='Zombie Mansion released for the iPhone'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-9183303179935598277</id><published>2008-11-23T16:35:00.003+13:00</published><updated>2008-11-24T10:02:39.194+13:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iphone development'/><title type='text'>iPhone Dev: "The binary you uploaded was invalid. The signature was invalid, or it was not signed with an Apple submission certificate."</title><content type='html'>I finally finished my iPhone game this week (&lt;a href="http://sourceitsoftware.com/zombie.html"&gt;Zombie Mansion&lt;/a&gt;).  All I had to do on Saturday was upload the it into the App store and spend the rest of the weekend relaxing at the beach.&lt;br /&gt;&lt;br /&gt;Not so fast.  I have spent all weekend battling the dreaded "The binary you uploaded was invalid. The signature was invalid, or it was not signed with an Apple submission certificate." error.  As is often the case with error messages, the message itself was on no use what so ever in solving the problem.  It was in fact a positive hindrance as I spent several hours redoing my distribution certificates, provisioning profiles  and waving dead chickens (frozen) over my keyboard.&lt;br /&gt;&lt;br /&gt;In the end I resolved it by moving my dev folder off the thumb drive (fat 32 formatted) and onto the main Mac partition (Mac OS ext format) and rebuilding.&lt;br /&gt;&lt;br /&gt;For the benefit of any other poor buggers in the same straits, here is a list of tips I picked up while investigating this:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Build on a Max OS Est formated drive (you only need to do this for the App store build)&lt;/li&gt;&lt;li&gt;Make sure you have a 57*57 icon called (case sensitive) "Icon.png"&lt;/li&gt;&lt;li&gt;Check the spelling of the code signing identity&lt;/li&gt;&lt;li&gt;make sure your bundle app id is correct&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Make sure the app bundle contains the following:&lt;br /&gt; CodeResources&lt;br /&gt; _CodeSignature&lt;br /&gt; embedded.mobileprovision&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;One think I found helpful was having an ad-hoc version.  That let me sort out problems with certificates much more easily than doing continuous uploads.&lt;br /&gt;&lt;br /&gt;Links:&lt;br /&gt;iPhone Dev forums discussion: &lt;a href="https://devforums.apple.com/message/12311#12311"&gt;https://devforums.apple.com/message/12311#12311&lt;/a&gt;&lt;br /&gt;Zombie Mansion: &lt;a href="http://sourceitsoftware.com/zombie.html"&gt;http://sourceitsoftware.com/zombie.html&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-9183303179935598277?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/9183303179935598277/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=9183303179935598277' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/9183303179935598277'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/9183303179935598277'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2008/11/iphone-dev-binary-you-uploaded-was.html' title='iPhone Dev: &quot;The binary you uploaded was invalid. The signature was invalid, or it was not signed with an Apple submission certificate.&quot;'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-1099384595661412938</id><published>2008-10-13T09:46:00.003+13:00</published><updated>2008-10-13T09:53:37.503+13:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='delphi programming'/><category scheme='http://www.blogger.com/atom/ns#' term='dunit'/><title type='text'>Getting line numbers in dunit test</title><content type='html'>I forget this every time:(&lt;br /&gt;&lt;br /&gt;By default, dunit gives the the address of where your unit tests failed.&lt;br /&gt;To get the line numbers instead, do the following:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Install the JCL from http://sourceforge.net/projects/jcl&lt;/li&gt;&lt;li&gt;In your test project settings, add the conditional define USE_JEDI_JCL (Directories/Conditionals page)&lt;/li&gt;&lt;li&gt;In your test project settings, set Map File to detailed (Linker page)&lt;/li&gt;&lt;li&gt;Rebuild your project&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-1099384595661412938?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/1099384595661412938/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=1099384595661412938' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/1099384595661412938'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/1099384595661412938'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2008/10/getting-line-numbers-in-dunit-test.html' title='Getting line numbers in dunit test'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-605433301474684377</id><published>2008-09-16T16:44:00.005+12:00</published><updated>2008-09-17T09:10:22.068+12:00</updated><title type='text'>Delphi 2009 = A good test of my backup strategy</title><content type='html'>I installed Delphi 2009 today.  In a fit of enthusiasm, I installed it onto my Delphi 2007 virtual machine...&lt;br /&gt;&lt;br /&gt;That turned out not to be such a smart move.  Not only did d09 fail to install (stopping 1/2 way through with a 'failed to find setup.msi' error), but it trashed my d07 install as well.  I don't know how bad the trashing was, I killed delphi after the 10th "package not found error" on start up.&lt;br /&gt;&lt;br /&gt;I am not blaming CodeGear for this, my D07 install was "customised" to fit on a small virtual machine, with several, possibly important, folders deleted, and with little free space remaining.&lt;br /&gt;&lt;br /&gt;One of the many nice things about using a virtual machine is the ease of backups and recovery.  In this case, it came down to a 2 step process&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Copy fridays backup onto the computer&lt;/li&gt;&lt;li&gt;Use subversion to retrieve all the files changed since friday&lt;/li&gt;&lt;/ol&gt;Total elapsed time to recover was about 10 minutes, most of which was spent making coffee while waiting for the files to copy.&lt;br /&gt;&lt;br /&gt;Moral of the story:  If you are installing D2009 (or any other version), put it in a virtual machine.&lt;br /&gt;And use version control&lt;br /&gt;And backup regularly&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-605433301474684377?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/605433301474684377/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=605433301474684377' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/605433301474684377'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/605433301474684377'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2008/09/delphi-2009-good-test-of-my-backup.html' title='Delphi 2009 = A good test of my backup strategy'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-7354295145871359535</id><published>2008-08-18T09:45:00.005+12:00</published><updated>2008-08-18T12:00:11.309+12:00</updated><title type='text'>Programming for the iphone really sucks</title><content type='html'>Ogrampray, ergo sum.  I program, therefore I am.&lt;br /&gt;&lt;br /&gt;I have wanted to program nearly every device that I own (except for video recorders).&lt;br /&gt;Now that I have an iPhone, I want to program that.  Unfortunately there are a number of roadblocks in the way...&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;NDA&lt;/span&gt;&lt;br /&gt;The iPhone nda is ridiculously draconian.  There are enough posts on the subject that i won't do into details.  See &lt;a href="http://fuckingnda.com/"&gt;here&lt;/a&gt; if you want to know how developers feel about it.  Basically, you need to figure everything out yourself coz you can't ask anyone else.  There are still &lt;a href="http://groups.google.com/group/iphonesdkdevelopment?hl=en"&gt;discussion groups&lt;/a&gt;, but they may be gone tomorrow.  There is also a series of tutorials at &lt;a href="http://www.iphonesdkarticles.com/"&gt;IphoneSdkArticles.com&lt;/a&gt; but that may also disappear.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Objective C&lt;/span&gt;&lt;br /&gt;ATM, your choice of development language is Objective C or Objective C.&lt;br /&gt;If you are a windows developer, you first question is probably "Wtf is Objective C?".  The short answer is that it is yet another version of C with objects, designed by someone with an unholy fascination for square brackets.  The average line of code contains slightly more text than symbols, but only just.&lt;br /&gt;&lt;br /&gt;ObjC is primarily used on Apple machines, and sits at #42 in the &lt;a href="http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html"&gt;tiobe&lt;/a&gt; list, just below Erlang.&lt;br /&gt;&lt;br /&gt;Because it is Apple only, the development tools only run on OS X (you can use gcc on windows, see &lt;a href="http://wiki.iphonegameover.com/"&gt;here&lt;/a&gt;, but it's not easy).  The tools may be free, but you need a $1000 OS X machine to run it on.&lt;br /&gt;&lt;br /&gt;The sdk license expressly forbids interpretors, JITers and iPhone based compilers.  So the only way to get java or mono is if they develop an ahead of time complier.  Here's hoping.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Multitasking&lt;/span&gt;&lt;br /&gt;Nope, sorry, you don't need it.  Applications run full screen, single window.  When the user presses the home button, your app exits.  To get back to your app, the user needs to start it up all other again.  This immediately rules out a large number of interesting applications, and adds a certain amount of complication to development. As an aside, Windows Mobile does exactly the opposite and minimises applications rather than closing them, so they can reopen more quickly.  This approach is also arse.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Application sandbox&lt;/span&gt;&lt;br /&gt;Each application is stored in a single folder.  All files, settings and related documents are stored within that folder.  The application can only access the contents of their folder.  There is no concept of a user documents folder.  There is also no simple way to get documents onto the phone for use by your app.&lt;br /&gt;&lt;br /&gt;Example:  I have an ebook on my computer.  I would like to read it on my phone (I have kids, I spend a lot of time sitting in the car waiting).  On a windows mobile machine, a palm, or even my old Psion S5, you copy the file over onto your machine, and open it.  On a iPhone, it's not so easy,  Using ereader, I need to upload the ebook to their website, and then download it again on the iPhone.  Alternately, they helpfully suggest, I can run a web-server on my PC.&lt;br /&gt;On the other hand, the Stylus and Bookshelf book readers provide desktop software (50meg download, written in java) that will let you copy documents over using wi-fi.  If I ever need to transfer documents when I don't have a wi-fi router, I am in for a large amount of aggravation.&lt;br /&gt;&lt;br /&gt;So, if you are writing a app that needs to work with documents, you also need to write a client/server file transfer application, in a different programming language, just to get you document where you can use it!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Distribution&lt;/span&gt;&lt;br /&gt;As a means of getting your application to a large number of paying punters, App Store is not too bad.  The 30% commission is high compared to Paypal, Regnow, SwReg etc, but low compared to phone/pda specific sellers such as Handango.  However as a means of distributing your app to a specific group (ie company wide as opposed to world wide) it is less useful.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Positives&lt;/span&gt;&lt;br /&gt;There are some good points about iPhone development though.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The hardware is essentially the same (+/- 3g, gps) on every device.  This is a significant contrast to Windows Mobile where the screen size and orientation can change, there may or may not be a touch screen, camera, gps, wi-fi, internet etc).&lt;/li&gt;&lt;li&gt;Appstore makes purchasing applications dead easy.  I suspect that iPhone users will end up with more applications than windows mobile users.&lt;/li&gt;&lt;li&gt;The development tools are quite polished, and cheap if you already have an Apple machine.&lt;/li&gt;&lt;li&gt;The phone has lots of useful functionality.  GPS, wi-fi, accelerometers, camera etc.  I can't think of any other phone that has sold as well and has as many toys to play with. &lt;/li&gt;&lt;li&gt;The xcode development tools can also deal with C++ and C code, although the sdk is in Objective C.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;If you are a Apple developer, developing for the iPhone is a no-brainer.  For a windows developer, it is a much harder decision.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Links&lt;/span&gt;&lt;br /&gt;&lt;a href="http://fuckingnda.com/"&gt;NDA comments&lt;/a&gt;&lt;br /&gt;&lt;a href="http://groups.google.com/group/iphonesdkdevelopment?hl=en"&gt;SDK Discussion group&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.iphonesdkarticles.com/"&gt;iPhone SDK Articles&lt;/a&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Objective_c"&gt;Wikipedia on objective C&lt;br /&gt;&lt;/a&gt;&lt;a href="http://wiki.iphonegameover.com/"&gt;iPhone Development on Windows&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-7354295145871359535?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/7354295145871359535/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=7354295145871359535' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/7354295145871359535'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/7354295145871359535'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2008/08/programming-for-iphone-really-sucks.html' title='Programming for the iphone really sucks'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-5941413859656020338</id><published>2008-08-15T07:42:00.004+12:00</published><updated>2008-08-15T17:04:57.357+12:00</updated><title type='text'>Subversion add-ins for Delphi</title><content type='html'>Part 4 of a n part series on Subversion and delphi&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Subversion add-ins&lt;/span&gt;&lt;br /&gt;As we have already established, TortoiseSvn adds version control functionality to windows explorer.  This is all good, and the result is quite functional.  Many people need nothing more.   However for the rest of us, there are a number of ways to integrate subversion into delphi.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;File Browser&lt;/span&gt;&lt;br /&gt;If you have a recent version of delphi, and have TortoiseSvn installed then you get integration for free.  The File Browser window (View menu -&gt; File Browser) uses the Windows Explorer context menu so all TortoiseSvn commands also work with the File Browser&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_g2tNCh4si2M/SKUIqyX0pnI/AAAAAAAAAFY/zVc5yq1KjWs/s1600-h/DelphiFileExplorer.jpg"&gt;&lt;img style="cursor: pointer;" src="http://3.bp.blogspot.com/_g2tNCh4si2M/SKUIqyX0pnI/AAAAAAAAAFY/zVc5yq1KjWs/s320/DelphiFileExplorer.jpg" alt="" id="BLOGGER_PHOTO_ID_5234599673057289842" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;JCL Version&lt;/span&gt;&lt;br /&gt;The &lt;a href="http://homepages.codegear.com/jedi/jvcl/"&gt;jedi control library&lt;/a&gt; (jcl) includes a Tortoise (Svn and CVS) add-in that adds a JCL Version menu.  Most functionality is available, although I have never managed to get Diff working.  It requires Tortoise to be installed.  If you are already using Tortoise and the JCL, it's a bit of a no-brainer.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_g2tNCh4si2M/SKUIrGTKDXI/AAAAAAAAAFg/p0m3EJyeGkc/s1600-h/JclVersion.jpg"&gt;&lt;img style="cursor: pointer;" src="http://2.bp.blogspot.com/_g2tNCh4si2M/SKUIrGTKDXI/AAAAAAAAAFg/p0m3EJyeGkc/s320/JclVersion.jpg" alt="" id="BLOGGER_PHOTO_ID_5234599678406430066" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;Others&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;There are a few others that I haven't used.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://sourceforge.net/projects/delphisvn/"&gt;Delphi Svn&lt;/a&gt; is available from SourceForge.  It looks like it doesn't need Tortoise to be installed.&lt;/li&gt;&lt;li&gt;The gloriously named &lt;a href="http://delphiaddinfortortoisesvn.tigris.org/"&gt;delphiaddinfortortoisesvn&lt;/a&gt; is available from tigris.org, home of TortoiseSvn.  As you might expect, it requires Tortoise to be installed.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Links&lt;/span&gt;&lt;br /&gt;&lt;a href="http://tortoisesvn.tigris.org/"&gt;Tortoise&lt;/a&gt;&lt;br /&gt;&lt;a href="http://homepages.codegear.com/jedi/jvcl/"&gt;Jedi Control Library&lt;/a&gt;&lt;span style="font-family:Georgia,serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;a href="http://sourceforge.net/projects/delphisvn/"&gt;Delphi Svn&lt;/a&gt;&lt;br /&gt;&lt;a href="http://delphiaddinfortortoisesvn.tigris.org/"&gt;Delphi Addin (Tigris)&lt;br /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-5941413859656020338?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/5941413859656020338/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=5941413859656020338' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/5941413859656020338'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/5941413859656020338'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2008/08/subversion-add-ins-for-delphi.html' title='Subversion add-ins for Delphi'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_g2tNCh4si2M/SKUIqyX0pnI/AAAAAAAAAFY/zVc5yq1KjWs/s72-c/DelphiFileExplorer.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-4363715716546115171</id><published>2008-07-28T10:00:00.004+12:00</published><updated>2008-08-07T22:54:14.914+12:00</updated><title type='text'>Common tasks with Subversion</title><content type='html'>Part 3 of an n part series.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;General workflow for version control&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The following descriptions all use TortoiseSVN and Explorer.  The steps can also be done using other Subversion clients such as DelphiSvn or JCL.&lt;br /&gt;&lt;br /&gt;The general workflow for changing code is:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;span style="font-style: italic;"&gt;Update&lt;/span&gt;. Right click on your base development folder and choose TortoiseSvn -&gt; Update.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Resolve conflicts&lt;/li&gt;&lt;li&gt;code like a demon...&lt;/li&gt;&lt;li&gt;Test, test and test&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span&gt;Update  &lt;/span&gt;(again).  As 1, just in case someone else has changed things&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Resolve conflicts (again)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-style: italic;"&gt;Add &lt;/span&gt;(also &lt;span style="font-style: italic;"&gt;Delete &lt;/span&gt;and &lt;span style="font-style: italic;"&gt;Ignore&lt;/span&gt; as required)&lt;br /&gt;&lt;/li&gt;&lt;li style="font-style: italic;"&gt;Commit&lt;/li&gt;&lt;/ol&gt;Notes:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Solo developers can normally leave out steps 1,2,5,6&lt;/li&gt;&lt;li&gt;Steps 7 and 8 can be combined (check the "Show unversioned files" box in the commit dialog)&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;For a solo developer, the process essentially comes down to&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-style: italic;"&gt;Commit&lt;/span&gt;.  Do &lt;span style="font-style: italic;"&gt;Add&lt;/span&gt;s, &lt;span style="font-style: italic;"&gt;Delete&lt;/span&gt;s etc from commit dialog&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Now isn't that easier than zipping up all your source code and archiving it.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Traps for young players&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Deletes and (particular) Renames should be done from within Explorer/Tortoise.&lt;/li&gt;&lt;li&gt;Do &lt;span style="font-style: italic;"&gt;commit&lt;/span&gt;s from the base directory where possible.  If you &lt;span style="font-style: italic;"&gt;commit &lt;/span&gt;further down the tree, then you need to do an &lt;span style="font-style: italic;"&gt;update &lt;/span&gt;before you can commit from the base.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;"&gt;(Edit) Team Version Control&lt;/span&gt;&lt;br /&gt;One thing I didn't point out first time round (thanks Lars).&lt;br /&gt;The golden rule of team version control:&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Only check in working code to the trunk.&lt;/span&gt;&lt;br /&gt;If you are working it a team environment, and you want to commit non working code then create a branch.  That will let you have all the benefits of version control without annoying everyone you work with.  Once you have completed your changes, merge your changes back into the trunk.  See the &lt;a href="http://tortoisesvn.net/docs/release/TortoiseSVN_en/index.html"&gt;manual&lt;/a&gt; for details.&lt;br /&gt;Also, Sean's rule number 2 (for team programming):&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Always update before you commit&lt;/span&gt; ()&lt;br /&gt;If you commit without an update first, the code in the repository may not be the same as your code.  That means that you don't know that the tests pass, and the code still compiles. &lt;br /&gt;&lt;br /&gt;E.g. Bob changes the signature of DoSomething to take an extra parameter.  It's in a file that you haven't touched, so there are no conflicts.  All of your code uses the old signature so when you commit, it won't compile any more.&lt;br /&gt;&lt;br /&gt;If you update first, you can catch the problem and avoid making a fool of yourself.  This sort of scenario can be quite common with larger teams.  Don't ask me how I know.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Manual&lt;/span&gt;&lt;br /&gt;All Tortoise commands are available from the Explorer context menu. See here for the &lt;a href="http://tortoisesvn.net/docs/release/TortoiseSVN_en/index.html"&gt;manual&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-4363715716546115171?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/4363715716546115171/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=4363715716546115171' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/4363715716546115171'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/4363715716546115171'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2008/07/common-tasks-with-subversion.html' title='Common tasks with Subversion'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-7233680244017094233</id><published>2008-07-26T15:22:00.003+12:00</published><updated>2008-07-26T15:44:43.492+12:00</updated><title type='text'>Subversion server options</title><content type='html'>I didn't cover subversion servers in my last &lt;a href="http://sourceitsoftware.blogspot.com/2008/07/starting-out-with-delphi-and-subversion.html"&gt;post&lt;/a&gt; as I don't use one any more.  However there have been some queries so here are a few ideas:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Windows installers&lt;/span&gt;&lt;br /&gt;&lt;a href="http://www.visualsvn.com/server/"&gt;VisualSVN Server&lt;/a&gt;&lt;br /&gt;&lt;a href="http://svn1clicksetup.tigris.org/"&gt;official Svn 1-click setup&lt;/a&gt;&lt;br /&gt;&lt;a href="http://subversion.tigris.org/"&gt;Other OS&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;VMWare appliances&lt;/span&gt;&lt;br /&gt;&lt;a href="http://www.vmware.com/appliances/directory/519"&gt;Subversion and WebSVN on Ubuntu Server&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.ytechie.com/svn-vm"&gt;SVN VM&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.garghouti.co.uk/vmTrac/"&gt;vmTrac &lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Online hosting&lt;br /&gt;&lt;/span&gt;&lt;a href="http://cvsdude.com/"&gt;Cvs Dude&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;a href="http://www.google.co.nz/search?q=subversion+hosting&amp;amp;ie=utf-8&amp;amp;oe=utf-8&amp;amp;aq=t&amp;amp;rls=org.mozilla:en-GB:official&amp;amp;client=firefox-a"&gt;Google search&lt;br /&gt;&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;I am not endorsing any of these.  However, if I needed a server, I would probably go with one of the online solutions.&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-7233680244017094233?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/7233680244017094233/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=7233680244017094233' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/7233680244017094233'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/7233680244017094233'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2008/07/subversion-server-options.html' title='Subversion server options'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-2997035135586733179</id><published>2008-07-07T09:22:00.013+12:00</published><updated>2008-10-13T09:46:08.616+13:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='delphi programming'/><category scheme='http://www.blogger.com/atom/ns#' term='version control'/><title type='text'>Starting out with Delphi and subversion</title><content type='html'>I am always disturbed by the number of programmers I run into who don't use version control.  A version control system (VCS) is one of the fundamental tools of a programmer, up there with the ide/compiler, bug tracking and backups.&lt;br /&gt;&lt;br /&gt;Subversion, together with the TortoiseSvn plugin for Explorer, is one of the better free VCS solutions available.  What follows is a quick guide to setting it up the easy way.&lt;br /&gt;&lt;br /&gt;Note:  This setup is not suitable if you have a large number of users, or need to provide access across the internet.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Tortoise and Subversion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://subversion.tigris.org/"&gt;Subversion&lt;/a&gt; is the actual VCS.  Typically you would run it as a service and then connect to it with client software such as &lt;a href="http://tortoisesvn.tigris.org/"&gt;Tortoise&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Tortoise adds &lt;a href="http://tortoisesvn.tigris.org/ExplorerIntegration.html#contextmenus"&gt;context menus&lt;/a&gt; and &lt;a href="http://tortoisesvn.tigris.org/ExplorerIntegration.html#overlays"&gt;icon overlays&lt;/a&gt; to Explorer allowing control of the VCS.  These menus and overlays are also available in programs that use the Explorer menus and icons such as the Delphi File Explorer.&lt;br /&gt;&lt;br /&gt;Other clients for Subversion are also &lt;a href="http://subversion.tigris.org/links.html#clients"&gt;available&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;If you only have a limited number of users, and do not need remote access, you can use Tortoise without a subversion server.  This makes set-up much easier.  I am not going to cover setting up the server here, primarily because I haven't used one for 3 years.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;My file structure&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I have 2 base folders, D:\dev and d:\devother.&lt;br /&gt;&lt;br /&gt;D:\devother\ is used for files that are use different version control settings (ie open source projects that I update from their repository such as tiopf).&lt;br /&gt;D:\dev\ is used for everything else; my code, third party components, images etc.  Having everything under one folder makes version control easier.&lt;br /&gt;&lt;br /&gt;I recommend moving all source under a single base folder, if it is not already. If you have source on a network share, move it into a base folder on a local drive.  If you need to share source, place the repository on a shared folder.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Repository&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The repository is where the versions are stored.  It has a directory structure similar to a file structure.&lt;br /&gt;&lt;br /&gt;The subversion book recommends having the following directories at the repository root&lt;br /&gt;&lt;br /&gt;/branches/&lt;br /&gt;/trunk/&lt;br /&gt;/tags/&lt;br /&gt;&lt;br /&gt;With this layout, your main development takes place under /truck/.  Branches and tags go where you would expect.  I don't do a lot of branching and tagging, when I do I place the branch directories along side the main project directories instead.  Therefore I don't bother with the initial directories and create branch directories as required.&lt;br /&gt;&lt;br /&gt;My layout is more like&lt;br /&gt;&lt;br /&gt;/components/&lt;br /&gt;...&lt;br /&gt;/projects/&lt;br /&gt;/projects/project 1 v1/&lt;br /&gt;/projects/project 1 v2/&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;This maps to my file structure of&lt;br /&gt;&lt;br /&gt;d:\dev\&lt;br /&gt;d:\dev\components\&lt;br /&gt;...&lt;br /&gt;d:\dev\projects&lt;br /&gt;d:\dev\projects\project 1 v1\&lt;br /&gt;d:\dev\projects\project 1 v2\&lt;br /&gt;...&lt;br /&gt;etc&lt;br /&gt;&lt;br /&gt;It is reasonably easy to change from one repository layout to another if you change your mind, so choose whichever structure makes sense to you..&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Setup&lt;/span&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Download and install Tortoise from &lt;a href="http://tortoisesvn.net/downloads"&gt;here&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;Open Windows Explorer&lt;/li&gt;&lt;li&gt;Create an empty folder to serve as your repository.  This can be local or on a network drive.  The location needs to be reasonably safe and easy to back up. &lt;/li&gt;&lt;li&gt;Right click on the folder and click on "Create repository here"&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_g2tNCh4si2M/SIAh2cRH-2I/AAAAAAAAAEw/A7RgEYBDV9Q/s1600-h/1+Create+repository.jpg"&gt;&lt;img style="cursor: pointer;" src="http://bp2.blogger.com/_g2tNCh4si2M/SIAh2cRH-2I/AAAAAAAAAEw/A7RgEYBDV9Q/s320/1+Create+repository.jpg" alt="" id="BLOGGER_PHOTO_ID_5224212786934446946" border="0" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Choose "Native filesystem"&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_g2tNCh4si2M/SIAhsfVjUsI/AAAAAAAAAEI/iAlZAWCKVLU/s1600-h/2+file+system.jpg"&gt;&lt;img style="cursor: pointer;" src="http://bp2.blogger.com/_g2tNCh4si2M/SIAhsfVjUsI/AAAAAAAAAEI/iAlZAWCKVLU/s320/2+file+system.jpg" alt="" id="BLOGGER_PHOTO_ID_5224212615959630530" border="0" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;If you want to set up /branches/, /tags/ and /truck/ directories, right click on your repository folder and choose TortoiseSvn -&gt; Repo-browser.  Right click on the root directory and choose "Create Folder" for each of the initial directories.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Right click on any folder and choose TortoiseSvn -&gt; Settings&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_g2tNCh4si2M/SIAhs67izxI/AAAAAAAAAEY/76DA_DbBumU/s1600-h/4+settings.jpg"&gt;&lt;img style="cursor: pointer;" src="http://bp3.blogger.com/_g2tNCh4si2M/SIAhs67izxI/AAAAAAAAAEY/76DA_DbBumU/s320/4+settings.jpg" alt="" id="BLOGGER_PHOTO_ID_5224212623366737682" border="0" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;In the Global ignore patterns, enter in the file types that should be ignored by default.  Ie things like map files that will (almost) never need to be under version control.  I use "*.dcu *.~* dcu temp *.exe *.zip *.bkm *.ddp *.cfg *.dof *.dsk *.ini *.hlp *.gid *.bmp *.png *.gif ~* *.log bin debug release *.map *.chm *.bkf Thumbs.db *.mdb .obj *.elf *.stat *.ddp *.bpl *.map *.GID *.hlp *.opt *.dll *.raw *.BIN *.obj *.pdb *.scc Debug Release *.xml obj *.~* *.backup *.INI *.ArmLog *.KeyLog *.NanoLog *.Stats *.PreARM *.old *.drc *.*~ *.doc *.pdf *.bmp *.jpg *.MRW *.NEF *.ORF *.psd  *.X3F __history *.local *.identcache *.bak Thumbs.db *.ldb *.dex *.rar DllDcu *.lck CVS cvs *.txt *.TXT *.jdbg *.HLP *.KWF *.xls *.cnt *.dsm *.dti *.tmp *.lnk *.cbk *.mes"&lt;br /&gt;Note that the patterns are case sensitive.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_g2tNCh4si2M/SIAhtALlAdI/AAAAAAAAAEg/XQr-pqgNUgI/s1600-h/5+global+ignores.jpg"&gt;&lt;img style="cursor: pointer;" src="http://bp3.blogger.com/_g2tNCh4si2M/SIAhtALlAdI/AAAAAAAAAEg/XQr-pqgNUgI/s320/5+global+ignores.jpg" alt="" id="BLOGGER_PHOTO_ID_5224212624776167890" border="0" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Initial Import&lt;/span&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Back up your source code!&lt;/li&gt;&lt;li&gt;Right click on your base development folder (I use d:\dev\) and click on "SVN Checkout"&lt;/li&gt;&lt;li&gt;Click on the browse button beside URL and navigate to the repository directory (if you have set up a /trunk/ directory, navigate to this).&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_g2tNCh4si2M/SIAhs_7g8KI/AAAAAAAAAEQ/Azi2Z7hP5m8/s1600-h/3+checkout.jpg"&gt;&lt;img style="cursor: pointer;" src="http://bp1.blogger.com/_g2tNCh4si2M/SIAhs_7g8KI/AAAAAAAAAEQ/Azi2Z7hP5m8/s320/3+checkout.jpg" alt="" id="BLOGGER_PHOTO_ID_5224212624708792482" border="0" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Right click on your base development folder (d:\dev\ in my case) and choose TortoiseSVN-&gt;Add.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_g2tNCh4si2M/SIAhtUY9YqI/AAAAAAAAAEo/CZzQw4w6a44/s1600-h/6+Add.jpg"&gt;&lt;img style="cursor: pointer;" src="http://bp0.blogger.com/_g2tNCh4si2M/SIAhtUY9YqI/AAAAAAAAAEo/CZzQw4w6a44/s320/6+Add.jpg" alt="" id="BLOGGER_PHOTO_ID_5224212630201000610" border="0" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Wait for the Add dialog to populate.  The first time it is used, it can take a while to populate.  Work your way down the file/folder list.&lt;br /&gt;If there is something you don't want to add now, uncheck the selection box.&lt;br /&gt;If you never want to add it, right click on the item and choose "Add to ignore list"&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_g2tNCh4si2M/SIAhjUCzWTI/AAAAAAAAADg/g5FfNRM0WP0/s1600-h/7+add+to+ignore+list.jpg"&gt;&lt;img style="cursor: pointer;" src="http://bp2.blogger.com/_g2tNCh4si2M/SIAhjUCzWTI/AAAAAAAAADg/g5FfNRM0WP0/s320/7+add+to+ignore+list.jpg" alt="" id="BLOGGER_PHOTO_ID_5224212458309376306" border="0" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Once you are happy with the selected files and folders, click OK.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_g2tNCh4si2M/SIAhjTNoJcI/AAAAAAAAADo/rw7fjjWbiOw/s1600-h/8+adding.jpg"&gt;&lt;img style="cursor: pointer;" src="http://bp3.blogger.com/_g2tNCh4si2M/SIAhjTNoJcI/AAAAAAAAADo/rw7fjjWbiOw/s320/8+adding.jpg" alt="" id="BLOGGER_PHOTO_ID_5224212458086344130" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;The files are now all added to version control.  However they have not yet been saved (committed).&lt;/li&gt;&lt;li&gt;Right click on the base development folder again and choose Commit.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_g2tNCh4si2M/SIAhjvHcQ_I/AAAAAAAAADw/Hdhmc5pWJrE/s1600-h/9+commit.jpg"&gt;&lt;img style="cursor: pointer;" src="http://bp0.blogger.com/_g2tNCh4si2M/SIAhjvHcQ_I/AAAAAAAAADw/Hdhmc5pWJrE/s320/9+commit.jpg" alt="" id="BLOGGER_PHOTO_ID_5224212465576592370" border="0" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Provide a message.  &lt;/li&gt;&lt;li&gt;Uncheck any files you don't want to commit at the moment and click OK.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_g2tNCh4si2M/SIAhjopJvKI/AAAAAAAAAD4/LnDC6jdkBH0/s1600-h/a+commit+diag.jpg"&gt;&lt;img style="cursor: pointer;" src="http://bp1.blogger.com/_g2tNCh4si2M/SIAhjopJvKI/AAAAAAAAAD4/LnDC6jdkBH0/s320/a+commit+diag.jpg" alt="" id="BLOGGER_PHOTO_ID_5224212463838936226" border="0" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;Your files are now under version control.  You can revert to any version, perform diffs, see what files are changed and perform all other sorts of good things.&lt;br /&gt;&lt;br /&gt;Version controlled files are marked to indicate their status.  A full list is given &lt;a href="http://tortoisesvn.tigris.org/ExplorerIntegration.html#overlays"&gt;here&lt;/a&gt;. The main ones are&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Committed: Check mark&lt;/li&gt;&lt;li&gt;Added: +&lt;/li&gt;&lt;li&gt;Changed: !&lt;/li&gt;&lt;li&gt;Deleted: x&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_g2tNCh4si2M/SIAhj41JLmI/AAAAAAAAAEA/-nDekJwuc6o/s1600-h/b+icons.jpg"&gt;&lt;img style="cursor: pointer;" src="http://bp2.blogger.com/_g2tNCh4si2M/SIAhj41JLmI/AAAAAAAAAEA/-nDekJwuc6o/s320/b+icons.jpg" alt="" id="BLOGGER_PHOTO_ID_5224212468184198754" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;To come&lt;/span&gt;&lt;br /&gt;I will do followup posts explaining&lt;br /&gt;&lt;ul&gt;&lt;li&gt;How to work with files on an ogoing basis&lt;/li&gt;&lt;li&gt;Various delphi integration options&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Links&lt;/span&gt;&lt;br /&gt;Subversion           &lt;a href="http://subversion.tigris.org/"&gt;http://subversion.tigris.org/&lt;/a&gt;&lt;br /&gt;Subversion book  &lt;a href="http://svnbook.red-bean.com/"&gt;http://svnbook.red-bean.com/&lt;/a&gt;&lt;br /&gt;Tortoise                &lt;a href="http://tortoisesvn.tigris.org/"&gt;http://tortoisesvn.tigris.org/&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-2997035135586733179?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/2997035135586733179/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=2997035135586733179' title='15 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/2997035135586733179'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/2997035135586733179'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2008/07/starting-out-with-delphi-and-subversion.html' title='Starting out with Delphi and subversion'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp2.blogger.com/_g2tNCh4si2M/SIAh2cRH-2I/AAAAAAAAAEw/A7RgEYBDV9Q/s72-c/1+Create+repository.jpg' height='72' width='72'/><thr:total>15</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-838133429563114251</id><published>2008-06-21T09:29:00.003+12:00</published><updated>2008-06-21T12:16:46.180+12:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='delphi'/><category scheme='http://www.blogger.com/atom/ns#' term='tiopf'/><category scheme='http://www.blogger.com/atom/ns#' term='database'/><title type='text'>ti Object persistance framework updated</title><content type='html'>&lt;span style="font-weight: bold;"&gt;What's up?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;v2.50 of tiOPF is now available at http://tiopf.sourceforge.net/&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;So what's tiOPF?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;tiOPF is a Object Persistence Framework. That is, it is a framework based around saving your objects to, and loading them from, databases and/or flat files.  See the &lt;a href="http://tiopf.sourceforge.net/Doc/overview/index.shtml"&gt;overview&lt;/a&gt; for more details.&lt;br /&gt;&lt;br /&gt;In a nutshell it lets you do things like:&lt;br /&gt;&lt;br /&gt;var&lt;br /&gt;  user: TMyuser;&lt;br /&gt;  userList: TUserList;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;  user:= Tuser.CreateNew;&lt;br /&gt;  user.FirstName:= 'Sean';&lt;br /&gt;  user.LastName:= 'cross';&lt;br /&gt;&lt;br /&gt;  user.Save;&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;  userList:= TUserList.Create;&lt;br /&gt;  userList.Load;&lt;br /&gt;&lt;br /&gt;  for user in userList do&lt;br /&gt;  ...&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;tiOPF handles the saving and loading of objects to databases and flat files.  You can swap between databases by initialising a new persistence layer.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Why should I care?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;tiOPF lets you code in objects rather than datasets (you can still use data aware controls though).  This gives you more object orientated code&lt;/li&gt;&lt;li&gt;tiOPF provides database independance&lt;/li&gt;&lt;li&gt;Better code reuse.  Because the persistance is separated out, you can use the same code across different databases and structures&lt;/li&gt;&lt;li&gt;Easier unit testing (in my experience anyway).  I find it much easier to setup objects and test them that to setup databases and test.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Links&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Home page:    &lt;a href="http://tiopf.sourceforge.net/"&gt;http://tiopf.sourceforge.net/&lt;/a&gt;&lt;br /&gt;Overview:      &lt;a href="http://tiopf.sourceforge.net/Doc/overview/index.shtml"&gt;http://tiopf.sourceforge.net/Doc/overview/index.shtml&lt;/a&gt;&lt;br /&gt;Newsgroups:  &lt;a href="http://tiopf.sourceforge.net/Support.shtml"&gt;http://tiopf.sourceforge.net/Support.shtml&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-838133429563114251?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/838133429563114251/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=838133429563114251' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/838133429563114251'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/838133429563114251'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2008/06/ti-object-persistance-framework-updated.html' title='ti Object persistance framework updated'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-5931460380729837463</id><published>2008-06-12T14:35:00.004+12:00</published><updated>2008-06-13T07:19:17.801+12:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='delphi'/><category scheme='http://www.blogger.com/atom/ns#' term='database'/><title type='text'>" Connection is busy with results for another hstmt"</title><content type='html'>One of the problems with working on the same program for years, is that you always end up paying for your sins.  In my case the sin in question is still using the bde and odbc.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.google.com/search?q=+Connection+is+busy+with+results+for+another+hstmt&amp;amp;ie=utf-8&amp;amp;oe=utf-8&amp;amp;aq=t&amp;amp;rls=org.mozilla:en-GB:official&amp;amp;client=firefox-a"&gt;"&lt;/a&gt;&lt;span id="thread_subject_site"&gt;&lt;a href="http://www.google.com/search?q=+Connection+is+busy+with+results+for+another+hstmt&amp;amp;ie=utf-8&amp;amp;oe=utf-8&amp;amp;aq=t&amp;amp;rls=org.mozilla:en-GB:official&amp;amp;client=firefox-a"&gt;Connection is busy with results for another hstmt"&lt;/a&gt; is a common error when connecting to ODBC databases.  It occurs because an OBDC connection can only have one active cursor at a time.  By default, odbc only retrieves the first 20 records for a query.  If the query contains more than 20 records, the rest are retrieved on demand.  That's all very well, but when you open a second query using same connection/session you get the dreaded hstmt error.&lt;br /&gt;&lt;br /&gt;I thought I had beaten it years ago, but my latest set of changes have resulted in the error reappearing.&lt;br /&gt;&lt;br /&gt;There are a few possible solutions to this error:&lt;br /&gt;&lt;/span&gt;&lt;ol&gt;&lt;li&gt;&lt;span id="thread_subject_site"&gt;Use TTable components.  These don't have the error as they open a new connection each time.  Not a very pretty solution :(&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span id="thread_subject_site"&gt;Put a FetchAll after each Open.  This forces the retrieval of all records.  Not practical in my case as I have around 250 tquery components to check.&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span id="thread_subject_site"&gt;Use multiple connections.  Also not practical for me.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span id="thread_subject_site"&gt;Replace the BDE with something else that doesn't have the problem.  In progress but...&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span id="thread_subject_site"&gt;Cheat.  Set the odbc rowset size to a larger number.  If you set it to 200, then the first 200 records will be returned.  If you set it to -1 then ALL records will be returned.  This could have dire effects on performance if your queries return a lot of records.&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;This time round I &lt;a href="http://groups.google.co.nz/group/borland.public.delphi.database.sqlservers/browse_thread/thread/962f220a8f7c3d08/9f2250500da34f5e?lnk=st&amp;amp;q=delphi+bde+hstmt+fetchall#9f2250500da34f5e"&gt;discovered&lt;/a&gt;, and went with option 5.&lt;br /&gt;&lt;br /&gt;To set the rowset size with the BDE, do the following:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Click on your TDatabase component&lt;/li&gt;&lt;li&gt;In the object inspector, expand Params&lt;/li&gt;&lt;li&gt;Put in a Key of "ROWSET SIZE"&lt;/li&gt;&lt;li&gt;Put in the desired value&lt;/li&gt;&lt;/ol&gt;Changing the rowset size should work with other odbc connection components as well.&lt;br /&gt;&lt;span id="thread_subject_site"&gt;&lt;br /&gt;Update:  As Otto has pointed out, the error can also be resolved, if you are using sql server 2005 or later, by using the SQL Native Client drivers.  See &lt;a href="http://msdn.microsoft.com/en-us/library/ms345109.aspx"&gt;Multiple Active Record Sets&lt;/a&gt; for more details.  Doesn't help me though :(&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-5931460380729837463?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/5931460380729837463/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=5931460380729837463' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/5931460380729837463'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/5931460380729837463'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2008/06/connection-is-busy-with-results-for.html' title='&quot; Connection is busy with results for another hstmt&quot;'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-4915212885804980666</id><published>2008-06-08T20:41:00.006+12:00</published><updated>2008-06-08T21:40:35.548+12:00</updated><title type='text'>Coverflow update</title><content type='html'>&lt;span style="font-weight: bold;"&gt;TMS GUIMotions&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;TMS Software have released their 3d animation component, GUIMotions.  It includes a number of animations including a coverflow effect.  More info is available &lt;a href="http://www.tmssoftware.com/site/guimotions.asp"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;My GLScene example&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I have updated my coverflow example.  I have included mirroring, multiple rows, vertical layout and a few other changes making easier to be reused.  I have also shown how to use standard vcl controls.&lt;br /&gt;&lt;br /&gt;You can download the latest version from &lt;a href="http://www.sourceitsoftware.com/download/delphi/CoverTest.zip"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_g2tNCh4si2M/SEugrOIe2hI/AAAAAAAAABo/MBKAU3qGLqg/s1600-h/WithControl.jpg"&gt;&lt;img style="cursor: pointer;" src="http://bp3.blogger.com/_g2tNCh4si2M/SEugrOIe2hI/AAAAAAAAABo/MBKAU3qGLqg/s320/WithControl.jpg" alt="" id="BLOGGER_PHOTO_ID_5209434058372602386" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;Using an editable  TMemo control&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_g2tNCh4si2M/SEukc_i5FwI/AAAAAAAAACA/MdFXCvh24jk/s1600-h/Trans.jpg"&gt;&lt;img style="cursor: pointer;" src="http://bp1.blogger.com/_g2tNCh4si2M/SEukc_i5FwI/AAAAAAAAACA/MdFXCvh24jk/s320/Trans.jpg" alt="" id="BLOGGER_PHOTO_ID_5209438211985184514" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;2x2, Transitioning from horizontal to vertical layout&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_g2tNCh4si2M/SEuiDdhnayI/AAAAAAAAAB4/dfjgwp2s77o/s1600-h/Vertical.jpg"&gt;&lt;img style="cursor: pointer;" src="http://bp1.blogger.com/_g2tNCh4si2M/SEuiDdhnayI/AAAAAAAAAB4/dfjgwp2s77o/s320/Vertical.jpg" alt="" id="BLOGGER_PHOTO_ID_5209435574333041442" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;Vertical layout, 2 across&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_g2tNCh4si2M/SEuiDLRWY4I/AAAAAAAAABw/8uFeigh2e68/s1600-h/Dual.jpg"&gt;&lt;img style="cursor: pointer;" src="http://bp3.blogger.com/_g2tNCh4si2M/SEuiDLRWY4I/AAAAAAAAABw/8uFeigh2e68/s320/Dual.jpg" alt="" id="BLOGGER_PHOTO_ID_5209435569432978306" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;Horizontal layout 2 across&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Links&lt;/span&gt;&lt;br /&gt;&lt;a href="http://www.tmssoftware.com/site/guimotions.asp"&gt;GuiMotions&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.sourceitsoftware.com/download/delphi/CoverTest.zip"&gt;GLScene coverflow demo&lt;/a&gt;&lt;br /&gt;&lt;a href="http://glscene.sourceforge.net/wikka/HomePage"&gt;GLScene&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-4915212885804980666?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/4915212885804980666/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=4915212885804980666' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/4915212885804980666'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/4915212885804980666'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2008/06/coverflow-update.html' title='Coverflow update'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp3.blogger.com/_g2tNCh4si2M/SEugrOIe2hI/AAAAAAAAABo/MBKAU3qGLqg/s72-c/WithControl.jpg' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-4462518182921163951</id><published>2008-05-16T09:24:00.010+12:00</published><updated>2008-05-30T23:03:01.168+12:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='delphi'/><title type='text'>Coverflow example using Delphi and GLScene</title><content type='html'>Problem&lt;br /&gt;I am beginning work on &lt;a href="http://www.picsprint.com/"&gt;Pics Print 4&lt;/a&gt;.  One of the things I want to do with this release is make it significantly more slick.  To that end, I thought "Coverflow".  See &lt;a href="http://flashloaded.com/flashcomponents/photoflow/example1.html"&gt;here&lt;/a&gt; for an example&lt;br /&gt;&lt;br /&gt;The trouble is that there is not that much in the way of delphi examples.  I did find "Flying Cow", which is a Delphi implementation using OpenGl.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Flying Cow&lt;/span&gt;&lt;br /&gt;Flying Cow is a clone of Cover Flow written by Matías Andrés Moreno (&lt;a href="http://www.matiasmoreno.com.ar/"&gt;http://www.matiasmoreno.com.ar/&lt;/a&gt; website currently down)&lt;br /&gt;&lt;br /&gt;Changes to make Flying Cow compile under D2007, and download links, are listed in &lt;a href="http://www.aqua-soft.org/board/showthread.php?t=46566"&gt;http://www.aqua-soft.org/board/showthread.php?t=46566&lt;/a&gt; (website currently down as well)&lt;br /&gt;&lt;br /&gt;Flying Cow looks quite nice.  However it has one huge drawback from my point of view, it uses the GPL and is therefore unsuitable for my use.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_g2tNCh4si2M/SCyt6OrK25I/AAAAAAAAAA4/xyu2vjX8q6U/s1600-h/Coverflow.jpg"&gt;&lt;img style="cursor: pointer;" src="http://bp0.blogger.com/_g2tNCh4si2M/SCyt6OrK25I/AAAAAAAAAA4/xyu2vjX8q6U/s400/Coverflow.jpg" alt="" id="BLOGGER_PHOTO_ID_5200722885589261202" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Flying Cow implementation&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;GLScene implimentation&lt;/span&gt;&lt;br /&gt;I have created my own version using &lt;a href="http://glscene.sourceforge.net/wikka/HomePage"&gt;GLScene&lt;/a&gt;.  Considering that I haven't done any 3d work since 2005 (on a pda using C++ at that), it was remarkably easy to get going without cracking open my OpenGL books.&lt;br /&gt;&lt;br /&gt;Here is the result:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_g2tNCh4si2M/SCy2XerK27I/AAAAAAAAABI/Jl1SKpSJibs/s1600-h/CoverTest1.jpg"&gt;&lt;img style="cursor: pointer;" src="http://bp1.blogger.com/_g2tNCh4si2M/SCy2XerK27I/AAAAAAAAABI/Jl1SKpSJibs/s320/CoverTest1.jpg" alt="" id="BLOGGER_PHOTO_ID_5200732184193457074" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;Basic layout&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_g2tNCh4si2M/SCy2lurK28I/AAAAAAAAABQ/A5L1hban5Fg/s1600-h/CoverTest2.jpg"&gt;&lt;img style="cursor: pointer;" src="http://bp2.blogger.com/_g2tNCh4si2M/SCy2lurK28I/AAAAAAAAABQ/A5L1hban5Fg/s320/CoverTest2.jpg" alt="" id="BLOGGER_PHOTO_ID_5200732429006592962" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;Showing 2 images across, and using transparency on mouseover to show hidden images.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_g2tNCh4si2M/SCzsjurK29I/AAAAAAAAABY/rxFKXrmhLcY/s1600-h/CoverTest1.jpg"&gt;&lt;img style="cursor: pointer;" src="http://bp2.blogger.com/_g2tNCh4si2M/SCzsjurK29I/AAAAAAAAABY/rxFKXrmhLcY/s320/CoverTest1.jpg" alt="" id="BLOGGER_PHOTO_ID_5200791768274754514" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;Now with added mirroring goodness&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_g2tNCh4si2M/SD_cHr5-V3I/AAAAAAAAABg/L5obLTsumXQ/s1600-h/2x2.jpg"&gt;&lt;img style="cursor: pointer;" src="http://bp1.blogger.com/_g2tNCh4si2M/SD_cHr5-V3I/AAAAAAAAABg/L5obLTsumXQ/s320/2x2.jpg" alt="" id="BLOGGER_PHOTO_ID_5206121718866663282" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;Now with vertical layout, showing 2 across and 2 down&lt;br /&gt;&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;You can download my source and the executable from &lt;a href="http://www.sourceitsoftware.com/download/delphi/CoverTest.zip"&gt;here&lt;/a&gt;.  It is written in D2007 but should be easily portable to earlier version (there may be a for ... in loop or two but that is about it).&lt;br /&gt;&lt;br /&gt;This is prototype code, not production code so be warned.  I take no responsibility if it eats your homework, backchats your mother-in-law or transfers all your money into my bank account.  On the plus side, it has a promiscuous license so you can use it in your own apps without problems.&lt;br /&gt;&lt;br /&gt;If you make any improvements, let me know and I will update source accordingly.&lt;br /&gt;&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;Update&lt;br /&gt;&lt;/span&gt;&lt;span&gt;Mirroring added&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Update 2 - May 30&lt;/span&gt;&lt;br /&gt;Code changed to use an object list instead of an array, removed Graphics32, given optional vertical layout, allows multiple rows, and demonstrates removing pages.&lt;br /&gt;&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Links&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;Javascript implimentation&lt;br /&gt;&lt;a href="http://flashloaded.com/flashcomponents/photoflow/example1.html"&gt;http://flashloaded.com/flashcomponents/photoflow/example1.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Flying cow  discussion thread&lt;br /&gt;&lt;a href="http://www.aqua-soft.org/board/showthread.php?t=46566"&gt;http://www.aqua-soft.org/board/showthread.php?t=46566&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;GLScene&lt;br /&gt;&lt;a href="http://glscene.sourceforge.net/wikka/HomePage"&gt;http://glscene.sourceforge.net/wikka/HomePage&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;My version&lt;br /&gt;&lt;a href="http://www.sourceitsoftware.com/download/delphi/CoverTest.zip"&gt;http://www.sourceitsoftware.com/download/delphi/CoverTest.zip&lt;/a&gt;&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/7028181408582795486-4462518182921163951?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/4462518182921163951/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=4462518182921163951' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/4462518182921163951'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/4462518182921163951'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2008/05/coverflow-example-using-delphi-and.html' title='Coverflow example using Delphi and GLScene'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp0.blogger.com/_g2tNCh4si2M/SCyt6OrK25I/AAAAAAAAAA4/xyu2vjX8q6U/s72-c/Coverflow.jpg' height='72' width='72'/><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-1024780652760061397</id><published>2008-04-22T19:45:00.003+12:00</published><updated>2008-04-22T20:42:52.632+12:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='delphi'/><category scheme='http://www.blogger.com/atom/ns#' term='database'/><title type='text'>Database versioning part 2</title><content type='html'>In &lt;a href="http://sourceitsoftware.blogspot.com/2008/04/database-versioning-part-1.html"&gt;part 1&lt;/a&gt;, I discussed database versioning with MS SQL Server.  SQL Server has robust tools available that simplifies the process of differencing and creating upgrade scripts.  DBISAM doesn't have these tools, but using datamodules and table components makes versioning close to painless.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Situation 2&lt;/span&gt;&lt;br /&gt;Delphi app&lt;br /&gt;DBISAM database&lt;br /&gt;1 developer&lt;br /&gt;&lt;br /&gt;&lt;a href="http://sourceitsoftware.com/rpm/index.html"&gt;Rental Property Manager&lt;/a&gt; uses a DBISAM database (DBISAM v3 in RPM 1, DBISAM v4 in RPM 2).  In the 4 years since it was released, it has been through about 20 changes.&lt;br /&gt;&lt;br /&gt;Unlike sql server, there is no database comparison utility to generate upgrade scripts.  That means things have to be done a bit differently.&lt;br /&gt;&lt;br /&gt;I still use the same general process as for sql server:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Record the database version number in the database&lt;/li&gt;&lt;li&gt;Define the expected db version in the application&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Keep a master db for comparison&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Only make one set of changes at a time&lt;/li&gt;&lt;li&gt;Automate differencing as much as possible&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Unit test, test and test again.  The tests should fail the moment a table is modified.&lt;/li&gt;&lt;/ol&gt;Because dbisam doesn't support views, the version number is stored (along with a bunch of other info) in an ini file in the database directory.&lt;br /&gt;&lt;br /&gt;I have a datamodule, TdmodCheckDatabase.  This has a TdbisamTable component for every table in the database.  The table component contains all fields in the table and is updated whenever the table is changed.&lt;br /&gt;&lt;br /&gt;To make database changes, the following process was used:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Increase the version number in the application&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Make and test DB changes.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Update the affected tables in TdmodCheckDatabase&lt;/li&gt;&lt;li&gt;If necessary (rarely) add further upgrade queries to TdmodCheckDatabase.  E.g. to set the values of new fields, or to add new data rows.&lt;/li&gt;&lt;li&gt;Generate a CreateDatabase unit script using the supplied database tools.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Update unit tests to suit the new db&lt;/li&gt;&lt;/ol&gt;When the application is run, it goes through the following process&lt;br /&gt;&lt;ol&gt;&lt;li&gt;If no database is found, then run CreateDatabase unit and then do step 3&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Get the current version number from the database ini file&lt;br /&gt;&lt;/li&gt;&lt;li&gt;If it is less than the expected version number then&lt;br /&gt;Run CreateDatabase  (to create any new tables)&lt;br /&gt;Check every table component in TdmodCheckDatabase&lt;br /&gt;Apply any table changes&lt;br /&gt;run any manual upgrade scripts&lt;/li&gt;&lt;li&gt;Update the version number in the database ini file.&lt;/li&gt;&lt;/ol&gt;In code this is:&lt;br /&gt;&lt;br /&gt;&lt;pre class="sourcecode"&gt;&lt;code&gt;&lt;br /&gt;&lt;b&gt;class&lt;/b&gt; &lt;b&gt;procedure&lt;/b&gt; TdmodCheckDatabase.UpgradeDatabase(databasePath: &lt;b&gt;string&lt;/b&gt;; currentVersion, newVersion: integer);&lt;br /&gt;&lt;b&gt;var&lt;/b&gt;&lt;br /&gt;module: TdmodCheckDatabase;&lt;br /&gt;f: integer;&lt;br /&gt;&lt;b&gt;begin&lt;/b&gt;&lt;br /&gt;module:= TdmodCheckDatabase.create(&lt;b&gt;nil&lt;/b&gt;);&lt;br /&gt;&lt;b&gt;try&lt;/b&gt;&lt;br /&gt;  module.OpenDatabase( databasePath );&lt;br /&gt;&lt;br /&gt;  &lt;b&gt;for&lt;/b&gt; f:= 0 &lt;b&gt;to&lt;/b&gt; module.ComponentCount -1  &lt;b&gt;do&lt;/b&gt;&lt;br /&gt;  &lt;b&gt;begin&lt;/b&gt;&lt;br /&gt;    &lt;b&gt;if&lt;/b&gt; module.Components[f] &lt;b&gt;is&lt;/b&gt; TDBISAMTable &lt;b&gt;then&lt;/b&gt;&lt;br /&gt;    &lt;b&gt;begin&lt;/b&gt;&lt;br /&gt;      &lt;b&gt;try&lt;/b&gt;&lt;br /&gt;        &lt;span style="color: rgb(0, 51, 153);"&gt;&lt;i&gt;// if we need to upgrade table to dbisam 4&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;        &lt;b&gt;if&lt;/b&gt; currentVersion &amp;lt;= DB_VERSION_FOR_DBISAM4 &lt;b&gt;then&lt;/b&gt;&lt;br /&gt;          TDBISAMTable(module.Components[f]).UpgradeTable;&lt;br /&gt;&lt;br /&gt;        module.UpgradeTable(TDBISAMTable(module.Components[f]));&lt;br /&gt;      &lt;b&gt;except&lt;/b&gt;&lt;br /&gt;       &lt;span style="color: rgb(0, 51, 153);"&gt;&lt;i&gt;// logging and error stuff removed&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;      &lt;b&gt;end&lt;/b&gt;;&lt;br /&gt;    &lt;b&gt;end&lt;/b&gt;;&lt;br /&gt;  &lt;b&gt;end&lt;/b&gt;;&lt;br /&gt;&lt;br /&gt;  &lt;b&gt;for&lt;/b&gt; f:= currentVersion + 1 &lt;b&gt;to&lt;/b&gt; newVersion &lt;b&gt;do&lt;/b&gt;&lt;br /&gt;    module.RunUpgradeScripts(f);&lt;br /&gt;&lt;br /&gt;  module.sqlMakeIndexes.ExecSQL; &lt;/code&gt;&lt;code&gt;&lt;span&gt;&lt;i&gt;&lt;span style="color: rgb(0, 51, 153);"&gt;&lt;i&gt;// have to create additional indexes manually&lt;/i&gt;&lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;/code&gt;&lt;code&gt;&lt;br /&gt; &lt;b&gt;finally&lt;/b&gt;&lt;br /&gt;  module.DBISAMDatabase1.Close;&lt;br /&gt;  module.free;&lt;br /&gt;&lt;b&gt;end&lt;/b&gt;;&lt;br /&gt;&lt;b&gt;end&lt;/b&gt;;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class="sourcecode"&gt;&lt;code&gt;&lt;br /&gt;&lt;b&gt;procedure&lt;/b&gt; TdmodCheckDatabase.UpgradeTable(table: TDBISAMTable);&lt;br /&gt;&lt;b&gt;var&lt;/b&gt;&lt;br /&gt; fieldIndex: integer;&lt;br /&gt; needsRestructure: boolean;&lt;br /&gt; canonical: TField;&lt;br /&gt;&lt;b&gt;begin&lt;/b&gt;&lt;br /&gt; needsRestructure:= false;&lt;br /&gt;&lt;br /&gt; table.FieldDefs.Update;&lt;br /&gt;&lt;br /&gt; &lt;span style="color:#003399;"&gt;&lt;i&gt;// add any new fields to the FieldDefs&lt;/i&gt;&lt;/span&gt;&lt;br /&gt; &lt;b&gt;if&lt;/b&gt; table.FieldDefs.Count &amp;lt; table.FieldCount &lt;b&gt;then&lt;/b&gt;&lt;br /&gt; &lt;b&gt;begin&lt;/b&gt;&lt;br /&gt;   &lt;b&gt;for&lt;/b&gt; fieldIndex := table.FieldDefs.Count &lt;b&gt;to&lt;/b&gt; table.Fields.Count -1 &lt;b&gt;do&lt;/b&gt;&lt;br /&gt;   &lt;b&gt;begin&lt;/b&gt;&lt;br /&gt;     table.FieldDefs.Add(fieldIndex + 1, table.Fields[fieldIndex].FieldName, table.Fields[fieldIndex].DataType, table.Fields[fieldIndex].Size, table.Fields[fieldIndex].Required);&lt;br /&gt;   &lt;b&gt;end&lt;/b&gt;;&lt;br /&gt;   needsRestructure:= true;&lt;br /&gt; &lt;b&gt;end&lt;/b&gt;;&lt;br /&gt;&lt;br /&gt; &lt;span style="color:#003399;"&gt;&lt;i&gt;// make sure we have correct size for string fields&lt;/i&gt;&lt;/span&gt;&lt;br /&gt; &lt;b&gt;for&lt;/b&gt; fieldIndex := 0 &lt;b&gt;to&lt;/b&gt; table.FieldDefs.Count -1 &lt;b&gt;do&lt;/b&gt;&lt;br /&gt; &lt;b&gt;begin&lt;/b&gt;&lt;br /&gt;   &lt;b&gt;if&lt;/b&gt; (table.FieldDefs[fieldIndex].DataType = ftString) &lt;b&gt;then&lt;/b&gt;&lt;br /&gt;   &lt;b&gt;begin&lt;/b&gt;&lt;br /&gt;     canonical:= table.FindField(table.FieldDefs[fieldIndex].Name);&lt;br /&gt;     &lt;b&gt;if&lt;/b&gt; assigned(canonical) &lt;b&gt;and&lt;/b&gt; (table.FieldDefs[fieldIndex].Size &amp;lt;&amp;gt; canonical.Size) &lt;b&gt;then&lt;/b&gt;&lt;br /&gt;   &lt;b&gt;begin&lt;/b&gt;&lt;br /&gt;     &lt;span style="color:#003399;"&gt;&lt;i&gt;// field size has changed&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;     needsRestructure:= true;&lt;br /&gt;     table.FieldDefs[fieldIndex].Size:= canonical.Size;&lt;br /&gt;   &lt;b&gt;end&lt;/b&gt;;&lt;br /&gt;   &lt;b&gt;end&lt;/b&gt;;&lt;br /&gt; &lt;b&gt;end&lt;/b&gt;;&lt;br /&gt;&lt;br /&gt; &lt;b&gt;if&lt;/b&gt; needsRestructure &lt;b&gt;then&lt;/b&gt;&lt;br /&gt;   table.AlterTable(); &lt;span style="color:#003399;"&gt;&lt;i&gt;// upgrades table using the new FieldDef values&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;&lt;b&gt;end&lt;/b&gt;;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;procedure&lt;/b&gt; TdmodCheckDatabase.RunUpgradeScripts(newVersion: integer);&lt;br /&gt;&lt;b&gt;begin&lt;/b&gt;&lt;br /&gt; &lt;b&gt;case&lt;/b&gt; newVersion &lt;b&gt;of&lt;/b&gt;&lt;br /&gt;   3: sqlVersion3.ExecSQL;&lt;br /&gt;   9: sqlVersion9.ExecSQL;&lt;br /&gt;   11: &lt;b&gt;begin&lt;/b&gt;  &lt;span style="color:#003399;"&gt;&lt;i&gt;// change to DBISAM 4&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;         sqlVersion11a.ExecSQL;&lt;br /&gt;         sqlVersion11b.ExecSQL;&lt;br /&gt;         sqlVersion11c.ExecSQL;&lt;br /&gt;         sqlVersion11d.ExecSQL;&lt;br /&gt;         sqlVersion11e.ExecSQL;&lt;br /&gt;       &lt;b&gt;end&lt;/b&gt;;&lt;br /&gt;   19: sqlVersion19.ExecSQL;&lt;br /&gt;   20: sqlVersion20.ExecSQL;&lt;br /&gt; &lt;b&gt;end&lt;/b&gt;;&lt;br /&gt;&lt;b&gt;end&lt;/b&gt;;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Unit tests included:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Make sure the current version is correct&lt;/li&gt;&lt;li&gt;Make sure that every table and every field exists&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Create a new blank database (for a number of different versions) and work though the upgrade process to make sure the final database is correct.&lt;/li&gt;&lt;li&gt;Restore an existing older database with data and upgrade to the latest version&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;With this process, altering the database structure is trivial for most changes.  Adding fields and table usually requires no more work than updating the table components and generating a new creation script . &lt;br /&gt;&lt;br /&gt;The current implementation does have a couple of restrictions in that it won't remove tables or fields.  However if that is required, it won't take long to add.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-1024780652760061397?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/1024780652760061397/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=1024780652760061397' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/1024780652760061397'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/1024780652760061397'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2008/04/database-versioning-part-2.html' title='Database versioning part 2'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-6659199736572505042</id><published>2008-04-17T14:19:00.004+12:00</published><updated>2008-04-22T20:38:57.364+12:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='delphi'/><category scheme='http://www.blogger.com/atom/ns#' term='database'/><title type='text'>Database versioning part 1</title><content type='html'>Versioning databases is one of those ongoing problems that has no one-size-fits-all solution.  There are 2 solutions I have developed  and used successfully.&lt;br /&gt;&lt;br /&gt;The general process I use each time is:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Record the database version number in the database&lt;/li&gt;&lt;li&gt;Define the expected db version the application&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Keep a master db for comparison&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Only make one set of changes at a time&lt;/li&gt;&lt;li&gt;Automate differencing as much as possible&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Unit test, test and test again.  The tests should fail the moment a table is modified.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Situation 1&lt;/span&gt;&lt;br /&gt;MSDE (= SQL server) database&lt;br /&gt;8 developers (pair programming)&lt;br /&gt;C# application&lt;br /&gt;&lt;br /&gt;Every developer had 2 databases, Unit Test db and Application Test DB (UnitDb and AppDb from now on).  With msde (now sql express) there are no licensing costs to worry about.&lt;br /&gt;There was also a Master database stored on a central server that served as the canonical reference.&lt;br /&gt;&lt;br /&gt;The database version number was stored in a view ('select xx as VersionNumber).&lt;br /&gt;&lt;br /&gt;To make database changes, the following process was used:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Check out the latest version of the app&lt;/li&gt;&lt;li&gt;Increase the version number in the application&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Make and test DB changes.  Usually this was done in UnitDB.  AppDb was kept synchronised using SQL Compare&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Update the version number in UnitDB&lt;/li&gt;&lt;li&gt;Generate an update script using Sql Compare.  Scripts were named Upgrade&lt;span style="font-weight: bold;"&gt;XXX&lt;/span&gt;.sql where XXX is the version that was being upgraded &lt;span style="font-weight: bold;"&gt;from&lt;/span&gt;.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Generate a CreateDatabase.sql script (for shipping with the app) and a CreateDatabase&lt;span style="font-weight: bold;"&gt;XXX&lt;/span&gt;.sql (for unit tests only) script.  In this case XXX is the version that will be created.  The 2 scripts are the same except for the name.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;If necessary (rarely) append further queries to the scripts.  E.g. to set the values of new fields, or to add new data rows.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Update unit tests to suit the new db&lt;/li&gt;&lt;li&gt;Check in changes&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;When the application is run, it goes through the following process&lt;br /&gt;&lt;ol&gt;&lt;li&gt;If no database is found, then run CreateDatabase.sql &lt;/li&gt;&lt;li&gt;Get the current version number from the database&lt;/li&gt;&lt;li&gt;If it is less than the expected version number then&lt;br /&gt;run UpgradeXXX.sql and go to 2&lt;/li&gt;&lt;/ol&gt;When the unit tests are run, the first step is to upgrade UnitDb to the current version using the same process as the main application.  That means that other peoples changes are automatically applied.  The unit tests included:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Make sure the current version is correct&lt;/li&gt;&lt;li&gt;Make sure that every table and every field exist (this doesn't always need to be explicit as the persistence unit tests should pick up any problems here).&lt;/li&gt;&lt;li&gt;Create a new blank database (for a number of different versions) and work though the upgrade process to make sure the final database is correct.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;The secret weapon in all this was sql compare which makes generating the scripts quite straight forward.&lt;br /&gt;Also the upgrade scripts can do more than one set of version changes.  ie Upgrade001.sql could upgrade the version to v10 so that scripts 002 - 009 don't need to be run.&lt;br /&gt;&lt;br /&gt;Situation 2 (delphi and dbisam) will follow in a later post.&lt;br /&gt;&lt;br /&gt;Links&lt;br /&gt;&lt;a href="http://www.red-gate.com/products/SQL_Compare/index.htm"&gt;Sql Compare&lt;br /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-6659199736572505042?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/6659199736572505042/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=6659199736572505042' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/6659199736572505042'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/6659199736572505042'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2008/04/database-versioning-part-1.html' title='Database versioning part 1'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-1540921463447198517</id><published>2008-03-02T20:42:00.004+13:00</published><updated>2008-03-11T10:43:24.099+13:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='delphi'/><category scheme='http://www.blogger.com/atom/ns#' term='vmware'/><title type='text'>VMWare tips</title><content type='html'>&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;Wireless networking&lt;/span&gt;&lt;br /&gt;By default vmware networks are set up as bridged.  However this doesn't work with Vista and wireless networks.&lt;br /&gt;&lt;br /&gt;The easy answer is to change the network setup to NAT.  However if you are doing server development this may not be much use.  In that case, you can try network bridging as described &lt;a href="http://mingstert.blogspot.com/2007/12/vmware-wireless-network-adapter-and.html"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Resizing the vm image.&lt;/span&gt;&lt;br /&gt;The easy way is to download the vm converter from &lt;a href="http://vmware.com/products/converter/"&gt;here&lt;/a&gt;.  Amoungst other things (creating an image from an existing computer) this can let you resize an image.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Performance&lt;/span&gt;&lt;br /&gt;If you have sufficent system memory, change VMWare settings to fit all virtual machine memory into reserved host ram  (Edit menu -&gt; Preferences, memory tab).   This will give a performance boost.&lt;br /&gt;&lt;br /&gt;Also, preallocate the hard drive space. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Links&lt;/span&gt;&lt;br /&gt;VMware Knowledgebase article - &lt;a href="http://kb.vmware.com/selfservice/dynamickc.do?cmd=show&amp;amp;forward=nonthreadedKC&amp;amp;docType=kc&amp;amp;externalId=1212&amp;amp;sliceId=2&amp;amp;stateId=0%200%209345265"&gt;http://kb.vmware.com/selfservice/dynamickc.do?cmd=show&amp;amp;forward=nonthreadedKC&amp;amp;docType=kc&amp;amp;externalId=1212&amp;amp;sliceId=2&amp;amp;stateId=0%200%209345265&lt;/a&gt;&lt;br /&gt;Bridging Process  &lt;a href="http://mingstert.blogspot.com/2007/12/vmware-wireless-network-adapter-and.html"&gt;http://mingstert.blogspot.com/2007/12/vmware-wireless-network-adapter-and.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;VM Converter &lt;a href="http://vmware.com/products/converter/"&gt;http://vmware.com/products/converter/&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-1540921463447198517?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/1540921463447198517/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=1540921463447198517' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/1540921463447198517'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/1540921463447198517'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2008/03/vmware-tips.html' title='VMWare tips'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-2841988832633209858</id><published>2008-02-26T10:50:00.007+13:00</published><updated>2008-02-28T09:30:02.816+13:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='delphi'/><category scheme='http://www.blogger.com/atom/ns#' term='tiopf'/><title type='text'>TIOPF - New persistance layer walkthrough</title><content type='html'>&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;TIOPF&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I use tiOPF for most new Delphi database applications.&lt;br /&gt;tiOPF is a Object Persistence Framework. That is, it is a framework based around saving your objects to, and loading them from, databases and/or flat files.&lt;br /&gt;&lt;br /&gt;See &lt;a href="http://tiopf.sourceforge.net/Doc/overview/index.shtml"&gt;overview&lt;/a&gt; for more details on tiOPF.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Persistence Layers (PL)&lt;/span&gt;&lt;br /&gt;TIOPF uses persistence layers to save/load objects. If you want to use an unsupported database, you just write another PL, and the required unit tests. The following is a walkthrough the process of creating and testing a new PL.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Corelab - SDAC&lt;/span&gt;&lt;br /&gt;I use Corelab's Sql Server Data Access Components for talking to MS Sql Server databases. This is faster than the BDE and ADO components I have used previously. However there is currently no PL for this...&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Step 1 - Base point&lt;/span&gt;&lt;br /&gt;Writing a PL involves the oldest form of code reuse - copy/paste.&lt;br /&gt;Find an existing PL similar to what you want. In this case, I will use ADOSQLServer. The ado sql server layer is slightly more complicated than most as it uses an abstract class shared with ado access. However this shouldn't be a problem.&lt;br /&gt;&lt;br /&gt;Because I am using a very similar persistance layer, the required changes are quite limited.  In many cases, I would need to alter the Connection string handling as well, amd perhaps the multithreading support.&lt;br /&gt;&lt;br /&gt;I need to copy the *ADOSQLServer files to *CrLabSDAC files, and then make the following substitutions:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;TMSConnection replaces TADOConnection&lt;/li&gt;&lt;li&gt;TMSQuery replaces TADOQuery&lt;/li&gt;&lt;li&gt;CrSDAC replaces ADOSQLServer&lt;/li&gt;&lt;li&gt;CrAbs replaces ADOAbs&lt;/li&gt;&lt;/ul&gt;+ the various uses replacements&lt;br /&gt;&lt;br /&gt;Using delphi's 'Find it Files', I searched for ADOSQLServer in the ..\tiOPF2\Trunk\ directory and subdirectories. It pulls up the following files:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;tiQueryADOSQLServer (which uses tiQueryADOAbs)&lt;/li&gt;&lt;li&gt;TTestTIPersistenceLayersADOSQLServer&lt;/li&gt;&lt;li&gt;tiTestDependencies&lt;/li&gt;&lt;li&gt;tiConstants&lt;/li&gt;&lt;li&gt;tiOPFManager&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;tiQueryADOSQLServer.pas is saved as tiQueryCrSdac.pas&lt;br /&gt;tiQueryADOAbs.pas is saved as tiQueryCrAbs.pas&lt;br /&gt;Both of these are saved in the \Options\ directory&lt;br /&gt;&lt;br /&gt;tiOPFADOSQLServer_TST.pas is saved as tiOPFCrSdac_TST.pas&lt;br /&gt;This is saved in the \UnitTests\Tests directory.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Step 2 Persistence Layer Changes&lt;/span&gt;&lt;br /&gt;In tiQueryCrAbs, I made the following changes:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;In the uses I replace ,ADODb with ,DBAccess, MSAccess&lt;/li&gt;&lt;li&gt;replace TADOConnection with TMSConnection&lt;/li&gt;&lt;li&gt;replace FADOConnection with FMSConnection&lt;/li&gt;&lt;li&gt;replace TADOQuery with TMSQuery&lt;/li&gt;&lt;li&gt;replace FADOQuery with FMSQuery&lt;/li&gt;&lt;li&gt;replace TtiQueryADO with TtiQueryCrSdac&lt;/li&gt;&lt;li&gt;replace TtiDatabaseADOAbs with TtiDatabaseCrAbs&lt;/li&gt;&lt;li&gt;replace cErrorADOCoInitialize with cErrorCrCoInitialize&lt;/li&gt;&lt;li&gt;replace EADOError with EDAError&lt;/li&gt;&lt;li&gt;replace cTIPersistADOSQLServer with cTIPersistCrSdac&lt;br /&gt;&lt;/li&gt;&lt;li&gt;delete cDelphi5ADOErrorString = '...';&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;In tiQueryCrSdac, I made the following changes:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;In the uses replace ,ADODb with ,DBAccess, MSAccess and tiQueryADOAbs with tiQueryCrAbs&lt;/li&gt;&lt;li&gt;replace ADOSQLServer with CrSdac&lt;/li&gt;&lt;li&gt;replace TtiDatabaseADOAbs with TtiDatabaseCrAbs&lt;/li&gt;&lt;li&gt;replace TADOTable with TMSTable&lt;/li&gt;&lt;li&gt;Delete the line TtiQueryCrSdac = class(TtiQueryADO);&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;In tiConstants, I added the line&lt;br /&gt;cTIPersistCrSdac = 'CrSdac';&lt;br /&gt;&lt;br /&gt;In tiOPFManager, I added the line&lt;br /&gt;{$IFDEF LINK_CRSDAC}       ,tiQueryCrSdac       {$ENDIF}&lt;br /&gt;below&lt;br /&gt;$IFDEF LINK_BDEPARADOX}   ,tiQueryBDEParadox   {$ENDIF}&lt;br /&gt;&lt;br /&gt;This means that the CR PL can be compiled in to applications by using LINK_CRSDAC in the conditional defines instead of adding the unit tiQueryCrSdac to the application.  This makes running the unit tests much easier as my local copy of the standard tests just need the define added&lt;br /&gt;&lt;br /&gt;Finally, I added the LINK_CRSDAC define to the DUNINTTIOPFGui appliciation and did a build.&lt;br /&gt;&lt;br /&gt;Some errors turned up in constructor TtiQueryCrSdac.Create; so I commented them out for now.  I found a few more compile errors as well due to the differences between SDAC and Ado components&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;replace ExecSQL with Execute&lt;/li&gt;&lt;li&gt;replace Parameters with Params&lt;/li&gt;&lt;li&gt;replace TParameter with TMSParam&lt;/li&gt;&lt;li&gt;replace CommitTrans with Commit&lt;/li&gt;&lt;li&gt;replace RollbackTrans with Rollback&lt;/li&gt;&lt;li&gt;replace BeginTrans with StartTransaction&lt;/li&gt;&lt;li&gt;replace ConnectionString with ConnectString&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Finally it all compiles.  I ran the unit tests to make sure I haven't broken anything yet.  I shouldn't have (yet) but ...&lt;br /&gt;&lt;br /&gt;8 minutes later, 1729 tests are run and passed.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Step 3 Unit Test changes &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In tiOPFCrSdac_TST, I made the following changes:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;replace ADOSQLServer with CrSdac&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;In tiTestDependencies, I made the following changes:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;added   ,tiOPFCrSdac_TST after   ,tiOPFADOSQLServer_TST&lt;/li&gt;&lt;li&gt;added   tiOPFCrSdac_TST.RegisterTests; after   tiOPFADOSQLServer_TST.RegisterTests;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Update&lt;/span&gt;:  Add the following define to the unit test properties: LINK_CRSDAC&lt;br /&gt;&lt;br /&gt;This now adds unit tests for the CrSdac PL.  It will run the same tests as the AdoSqlServer layer.  If necessary, I could override and alter the tests to accommodate database changes.&lt;br /&gt;&lt;br /&gt;Compile and run again.&lt;br /&gt;&lt;br /&gt;This time there are numerous errors.  In part, this is because this layer doesn't implement CreateDatabase and no default database has been defined.&lt;br /&gt;&lt;br /&gt;I ran the tests again.  In the Setup dialog, I clicked on the [Local Settings] button.  I added the following lines to the ini.&lt;br /&gt;[DB_CrSdac]&lt;br /&gt;DBName=localhost:tiopf&lt;br /&gt;UserName=NULL&lt;br /&gt;Password=&lt;br /&gt;&lt;br /&gt;This resolves most errors, leaving only 5.  I won't step through the process of fixing them.  They came down to:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;SDAC truncates long strings to 8000.  This needs further investigation&lt;/li&gt;&lt;li&gt;SDAC GetTableNames returns the owner as part of the name (eg 'dbo.MyTable') which needs to be removed.&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;"&gt;Step 4 Real data test&lt;/span&gt;&lt;br /&gt;In the unit tests for my real application, I added then tiQueryCrSdac unit.  I can now swap persistence layers by altering the connection string used in my application.&lt;br /&gt;&lt;br /&gt;Running the tests raises a couple more errors which are resolved by changing some of the SDAC query options.  Once that is done, and the tests all pass, I ran my application against some test data, and  real data.  All  works well.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Step 5 Build  a patch file&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Links&lt;/span&gt;&lt;br /&gt;TIOPF          &lt;a href="http://tiopf.sourceforge.net/"&gt;http://tiopf.sourceforge.net/&lt;/a&gt;&lt;br /&gt;Overview     &lt;a href="http://tiopf.sourceforge.net/Doc/overview/index.shtml"&gt;http://tiopf.sourceforge.net/Doc/overview/index.shtml&lt;/a&gt;&lt;br /&gt;Corelabs         &lt;a href="http://crlab.com/"&gt;http://crlab.com/&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-2841988832633209858?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/2841988832633209858/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=2841988832633209858' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/2841988832633209858'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/2841988832633209858'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2008/02/tiopf-new-persistance-layer-walkthrough.html' title='TIOPF - New persistance layer walkthrough'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-4223169727813219087</id><published>2008-02-01T10:05:00.001+13:00</published><updated>2008-02-26T10:50:05.224+13:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='delphi'/><category scheme='http://www.blogger.com/atom/ns#' term='remote control'/><title type='text'>Remote access to computers</title><content type='html'>&lt;span&gt;I spent a fair amount of time using one computer to look at/control another across the internet.  Over the past 5 years I have evaluated a number of products.  The following are some of my favourites.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Remote Desktop&lt;/span&gt;&lt;br /&gt;This is the best option across a wan, giving good performance.  However it is a pain in the proverbial to set up for use across the internet, as the ports are frequently blocked by firewalls.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;LogMeIn.com&lt;/span&gt;&lt;br /&gt;LogMeIn is the one I use must frequently, for controlling my personal computers.  A free account will let you control a reasonable number of computers (5 I think).  The paying version has additional features such as file access, sound and printing.  I have used the free version for about 5 years.&lt;br /&gt;&lt;br /&gt;Install is straight forward, go to the web site, log in, install software and go.  The software takes care of firewall and NAT issues in nearly every case. In 5 years, I only found one location where I couldn't get connectivity.&lt;br /&gt;&lt;br /&gt;There is software available for nearly everything, I have even used my windows mobile cellphone to control my pc.&lt;br /&gt;&lt;br /&gt;It's account based, so it is good for computers I own.  It is not so good for other computers where I don't have physical access beforehand as I obviously don't want to pass my account details around.  Once installed, the client pc can be unattended.&lt;br /&gt;&lt;br /&gt;GotoMyPc is an alternative, but they don't have a free version.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;CrossLoop&lt;/span&gt;&lt;br /&gt;I use crossloop (no relation) for remote user support.  They download and install crossloop and I do the same.  They click on the share button, send me the access code, and then I connect using the same access code.  Performance is not as good as LogMeIn, but it is usually adequate.&lt;br /&gt;&lt;br /&gt;It does require a user on the client machine to run the software, hit the share button and provide the access code.  It's free to use.&lt;br /&gt;&lt;br /&gt;CoPilot is an alternative which is probably better for Grandma and technically challenged users.  It's free on weekends, and $5 a day during the week.&lt;br /&gt;&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;Links&lt;/span&gt;&lt;br /&gt;&lt;a href="https://secure.logmein.com/home.asp"&gt;LogMeIn&lt;/a&gt;&lt;br /&gt;&lt;a href="https://www.gotomypc.com/"&gt;GotoMyPC&lt;/a&gt;&lt;br /&gt;&lt;a href="https://crossloop.com/"&gt;CrossLoop&lt;/a&gt;&lt;br /&gt;&lt;a href="https://www.copilot.com/"&gt;Copilot&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-4223169727813219087?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/4223169727813219087/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=4223169727813219087' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/4223169727813219087'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/4223169727813219087'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2008/02/remote-access-to-computers.html' title='Remote access to computers'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-3435974333306538379</id><published>2008-01-21T12:38:00.001+13:00</published><updated>2008-01-24T21:46:13.170+13:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='delphi'/><category scheme='http://www.blogger.com/atom/ns#' term='garbage collection'/><title type='text'>Garbage collection: Performance test</title><content type='html'>Following my &lt;a href="http://sourceitsoftware.blogspot.com/2008/01/garbage-collection-in-delphi-win-32-why.html"&gt;initial GC post,&lt;/a&gt; I received feedback regarding my comment "A well written and tuned garbage collector can be faster than manual allocation.".  These comments can be summarised as "show us the proof".&lt;br /&gt;&lt;br /&gt;I asked on the Boehm GC mailing list (if in doubt, ask for help).  The conversation starts &lt;a href="http://www.hpl.hp.com/hosted/linux/mail-archives/gc/2008-January/002072.html"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;They provided the following (my summary):&lt;br /&gt;&lt;ul&gt;&lt;li&gt;One benchmark is &lt;a href="http://www.cs.umass.edu/%7Eemery/pubs/gcvsmalloc.pdf"&gt;here&lt;/a&gt;, showing that speeds are comparable given sufficient memory (a gc will require more memory) .&lt;/li&gt;&lt;li&gt;Another is &lt;a href="http://www.hpl.hp.com/personal/Hans_Boehm/ismm/04tutorial.pdf"&gt;here&lt;/a&gt; from Hans Boehm's presentation.  See pages 50 onwards. He comments that it is a &lt;a href="http://www.hpl.hp.com/hosted/linux/mail-archives/gc/2008-January/002077.html"&gt;toy benchmark&lt;/a&gt;, on linux.&lt;/li&gt;&lt;li&gt;Malloc implementations have improved&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Code that favours manual allocation&lt;br /&gt;Simple create, do something, free&lt;br /&gt;Large objects&lt;/li&gt;&lt;li&gt;Code that favours gc&lt;br /&gt;Complicated lifetime management&lt;br /&gt;try ... finally, free&lt;br /&gt;multi threading&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Well that kinda helps.  But what about in delphi?&lt;br /&gt;&lt;br /&gt;I have done some quick tests using my modified version of the delphi wrapper for the Boehm GC (Delphi GC for short).  The modifications shouldn't make any major difference to the result.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Delphi benchmark 1:&lt;/span&gt;&lt;br /&gt;This is a simple, trivial, benchmark.  It creates 60,000,000 small objects and assigns a value.&lt;br /&gt;&lt;br /&gt;The object is simply:&lt;br /&gt;&lt;pre class="sourcecode"&gt;&lt;code&gt;&lt;br /&gt;TTestObject = &lt;b&gt;class&lt;/b&gt;&lt;br /&gt;&lt;b&gt;public&lt;/b&gt;&lt;br /&gt;Lines: TStrings;&lt;br /&gt;&lt;b&gt;constructor&lt;/b&gt; Create();&lt;br /&gt;&lt;b&gt;destructor&lt;/b&gt;  Destroy; &lt;b&gt;override&lt;/b&gt;;&lt;br /&gt;&lt;b&gt;end&lt;/b&gt;;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;and the test is simply&lt;br /&gt;&lt;pre class="sourcecode"&gt;&lt;code&gt;&lt;b&gt;for&lt;/b&gt; f := 1 &lt;b&gt;to&lt;/b&gt; TestCount &lt;b&gt;do&lt;/b&gt;&lt;br /&gt;&lt;b&gt;begin&lt;/b&gt;&lt;br /&gt;testObj:= TTestObject.Create;&lt;br /&gt;&lt;span style="color: rgb(0, 51, 153);"&gt;&lt;i&gt;{$ifdef USE_GC}&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;testObj.Lines.Add(&lt;span style="color: rgb(153, 51, 204);"&gt;'aaa'&lt;/span&gt;);&lt;br /&gt;&lt;span style="color: rgb(0, 51, 153);"&gt;&lt;i&gt;{$else}&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;&lt;b&gt;try&lt;/b&gt;&lt;br /&gt;testObj.Lines.Add(&lt;span style="color: rgb(153, 51, 204);"&gt;'aaa'&lt;/span&gt;);&lt;br /&gt;&lt;b&gt;finally&lt;/b&gt;&lt;br /&gt;testObj.Free;&lt;br /&gt;&lt;b&gt;end&lt;/b&gt;;&lt;br /&gt;&lt;span style="color: rgb(0, 51, 153);"&gt;&lt;i&gt;{$endif}&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;The try ... finally free section is not required by the GC version as we don't have to worry about memory leaks.&lt;br /&gt;&lt;br /&gt;The GC tests were repeated with a range of initial heap sizes and on different computers.  The FastMem test was also tried without the try finally.  The source code is available if anyone wants it.&lt;br /&gt;&lt;br /&gt;The results are&lt;br /&gt;&lt;br /&gt;&lt;table style="border-collapse: collapse; width: 462pt;" border="0" cellpadding="0" cellspacing="0" width="617"&gt;  &lt;colgroup&gt;   &lt;col style="width: 111pt;" width="148"&gt;   &lt;col style="width: 96pt;" width="128"&gt;   &lt;col style="width: 95pt;" width="127"&gt;   &lt;col style="width: 86pt;" width="115"&gt;   &lt;col style="width: 74pt;" width="99"&gt;  &lt;/colgroup&gt;  &lt;tbody&gt;&lt;tr style="height: 16.5pt;" height="22"&gt;   &lt;td style="border: medium none windowtext; padding: 0px; height: 16.5pt; width: 111pt; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;" height="22" width="148"&gt;   &lt;b&gt; &lt;/b&gt;&lt;br /&gt;&lt;/td&gt;   &lt;td style="border-style: none; border-color: windowtext windowtext windowtext -moz-use-text-color; border-width: medium; padding: 0px; width: 96pt; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;" width="128"&gt;   &lt;b&gt;Old laptop, 512mb&lt;/b&gt;&lt;/td&gt;   &lt;td style="border-style: none; border-color: windowtext windowtext windowtext -moz-use-text-color; border-width: medium; padding: 0px; width: 95pt; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;" width="127"&gt;   &lt;b&gt;Core 2, 2gig&lt;/b&gt;&lt;/td&gt;   &lt;td style="border-style: none; border-color: windowtext windowtext windowtext -moz-use-text-color; border-width: medium; padding: 0px; width: 86pt; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;" width="115"&gt;    &lt;b&gt;Single core 2 gig&lt;/b&gt;&lt;/td&gt;   &lt;td style="border-style: none; border-color: windowtext windowtext windowtext -moz-use-text-color; border-width: medium; padding: 0px; width: 74pt; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;" width="99"&gt;   &lt;b&gt;Quad core 3 gig&lt;/b&gt;&lt;/td&gt;  &lt;/tr&gt;  &lt;tr style="height: 15.75pt;" height="21"&gt;   &lt;td style="border-style: none; border-color: -moz-use-text-color windowtext windowtext; border-width: medium; padding: 0px; height: 15.75pt; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;" height="21"&gt;   &lt;b&gt;FMM (no try finally)&lt;/b&gt;&lt;/td&gt;   &lt;td style="border-style: none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium; padding: 0px; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;"&gt;&lt;br /&gt;&lt;/td&gt;   &lt;td style="border-style: none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium; padding: 0px; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;" align="right"&gt;approx 31.5&lt;/td&gt;   &lt;td style="border-style: none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium; padding: 0px; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;"&gt;&lt;br /&gt;&lt;/td&gt;   &lt;td style="border-style: none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium; padding: 0px; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;"&gt;&lt;br /&gt;&lt;/td&gt;  &lt;/tr&gt;  &lt;tr style="height: 15pt;" height="20"&gt;   &lt;td style="border-style: none; border-color: -moz-use-text-color windowtext windowtext; border-width: medium; padding: 0px; height: 15pt; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;" height="20"&gt;   &lt;b&gt;FMM try finally&lt;/b&gt;&lt;/td&gt;   &lt;td style="border-style: none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium; padding: 0px; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;" align="right"&gt;   81.281&lt;/td&gt;   &lt;td style="border-style: none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium; padding: 0px; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;" align="right"&gt;   33.306&lt;/td&gt;   &lt;td style="border-style: none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium; padding: 0px; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;" align="right"&gt;   37.875&lt;/td&gt;   &lt;td style="border-style: none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium; padding: 0px; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;" align="right"&gt;   48.046&lt;/td&gt;  &lt;/tr&gt;  &lt;tr style="height: 15pt;" height="20"&gt;   &lt;td style="border-style: none; border-color: -moz-use-text-color windowtext windowtext; border-width: medium; padding: 0px; height: 15pt; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;" height="20"&gt;   &lt;b&gt;GC 0mb&lt;/b&gt;&lt;/td&gt;   &lt;td style="border-style: none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium; padding: 0px; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;"&gt;&lt;br /&gt;&lt;/td&gt;   &lt;td style="border-style: none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium; padding: 0px; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;" align="right"&gt;   73.181&lt;/td&gt;   &lt;td style="border-style: none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium; padding: 0px; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;" align="right"&gt;   59.047&lt;/td&gt;   &lt;td style="border-style: none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium; padding: 0px; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;" align="right"&gt;   46.25&lt;/td&gt;  &lt;/tr&gt;  &lt;tr style="height: 15pt;" height="20"&gt;   &lt;td style="border-style: none; border-color: -moz-use-text-color windowtext windowtext; border-width: medium; padding: 0px; height: 15pt; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;" height="20"&gt;   &lt;b&gt;GC 5mb&lt;/b&gt;&lt;/td&gt;   &lt;td style="border-style: none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium; padding: 0px; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;"&gt;&lt;br /&gt;&lt;/td&gt;   &lt;td style="border-style: none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium; padding: 0px; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;" align="right"&gt;   39.499&lt;/td&gt;   &lt;td style="border-style: none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium; padding: 0px; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;" align="right"&gt;   32.906&lt;/td&gt;   &lt;td style="border-style: none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium; padding: 0px; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;" align="right"&gt;   29.656&lt;/td&gt;  &lt;/tr&gt;  &lt;tr style="height: 15pt;" height="20"&gt;   &lt;td style="border-style: none; border-color: -moz-use-text-color windowtext windowtext; border-width: medium; padding: 0px; height: 15pt; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;" height="20"&gt;   &lt;b&gt;GC 10mb&lt;/b&gt;&lt;/td&gt;   &lt;td style="border-style: none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium; padding: 0px; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;" align="right"&gt;   60.891&lt;/td&gt;   &lt;td style="border-style: none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium; padding: 0px; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;" align="right"&gt;   30.857&lt;/td&gt;   &lt;td style="border-style: none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium; padding: 0px; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;" align="right"&gt;   29.422&lt;/td&gt;   &lt;td style="border-style: none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium; padding: 0px; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;" align="right"&gt;   27.984&lt;/td&gt;  &lt;/tr&gt;  &lt;tr style="height: 15.75pt;" height="21"&gt;   &lt;td style="border-style: none; border-color: -moz-use-text-color windowtext windowtext; border-width: medium; padding: 0px; height: 15.75pt; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;" height="21"&gt;   &lt;b&gt;GC 20mb&lt;/b&gt;&lt;/td&gt;   &lt;td style="border-style: none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium; padding: 0px; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;" align="right"&gt;   58.328&lt;/td&gt;   &lt;td style="border-style: none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium; padding: 0px; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;" align="right"&gt;   26.926&lt;/td&gt;   &lt;td style="border-style: none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium; padding: 0px; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;" align="right"&gt;   27.437&lt;/td&gt;   &lt;td style="border-style: none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium; padding: 0px; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;" align="right"&gt;   27.062&lt;/td&gt;  &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_g2tNCh4si2M/R5RZo5mh_lI/AAAAAAAAAAo/KWKezQyXTdY/s1600-h/BenchMark.gif"&gt;&lt;img style="cursor: pointer;" src="http://bp2.blogger.com/_g2tNCh4si2M/R5RZo5mh_lI/AAAAAAAAAAo/KWKezQyXTdY/s400/BenchMark.gif" alt="" id="BLOGGER_PHOTO_ID_5157846032438132306" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Given a large enough initial heap, the gc version ends up faster than the FastMM version.&lt;br /&gt;&lt;br /&gt;This is not a serious benchmark, but it does indicate that a gc can be faster than manual allocation.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Delphi benchmark 2&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;For this, I added the gc to 2 of my existing unit tests.  It was a 2 line conversion, I just added the gc and set the initial heap size.&lt;br /&gt;&lt;br /&gt;Enable is a work injury management system.  It is heavy on database access and single threaded.&lt;br /&gt;Envisage is a document management system.  Database access is done via the &lt;a href="http://tiopf.sourceforge.net/"&gt;tiopf&lt;/a&gt; object persistence framework.  It reads pdf files, checks for bar codes and creates new ones.  It is multi-threaded.  It uses a large amount of memory.&lt;br /&gt;&lt;br /&gt;Here are the results:&lt;br /&gt;&lt;br /&gt;&lt;table style="border-collapse: collapse; width: 388pt;" border="0" cellpadding="0" cellspacing="0" width="518"&gt;  &lt;colgroup&gt;   &lt;col style="width: 111pt;" width="148"&gt;   &lt;col style="width: 96pt;" width="128"&gt;   &lt;col style="width: 95pt;" width="127"&gt;   &lt;col style="width: 86pt;" width="115"&gt;  &lt;/colgroup&gt;  &lt;tbody&gt;&lt;tr style="height: 15pt;" height="20"&gt;   &lt;td style="border: medium none ; padding: 0px; height: 15pt; width: 111pt; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;" height="20" width="148"&gt;&lt;br /&gt;&lt;/td&gt;   &lt;td style="border: medium none ; padding: 0px; width: 96pt; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;" width="128"&gt;   &lt;b&gt;Envisage, no threads&lt;/b&gt;&lt;/td&gt;   &lt;td style="border: medium none ; padding: 0px; width: 95pt; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;" width="127"&gt;   &lt;b&gt;Envisage, threaded&lt;/b&gt;&lt;/td&gt;   &lt;td style="border: medium none ; padding: 0px; width: 86pt; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;" width="115"&gt;   &lt;b&gt;Enable&lt;/b&gt;&lt;/td&gt;  &lt;/tr&gt;  &lt;tr style="height: 15pt;" height="20"&gt;   &lt;td style="border: medium none ; padding: 0px; height: 15pt; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;" height="20"&gt;   &lt;b&gt;FMM&lt;/b&gt;&lt;/td&gt;   &lt;td style="border: medium none ; padding: 0px; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;"&gt;                                      70 &lt;/td&gt;   &lt;td style="border: medium none ; padding: 0px; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;"&gt;                                114.4 &lt;/td&gt;   &lt;td style="border: medium none ; padding: 0px; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;"&gt;                              16.4 &lt;/td&gt;  &lt;/tr&gt;  &lt;tr style="height: 15pt;" height="20"&gt;   &lt;td style="border: medium none ; padding: 0px; height: 15pt; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;" height="20"&gt;   &lt;b&gt;GC 20&lt;/b&gt;&lt;/td&gt;   &lt;td style="border: medium none ; padding: 0px; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;"&gt;                                      74 &lt;/td&gt;   &lt;td style="border: medium none ; padding: 0px; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;"&gt;                                119.0 &lt;/td&gt;   &lt;td style="border: medium none ; padding: 0px; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;"&gt;&lt;br /&gt;&lt;/td&gt;  &lt;/tr&gt;  &lt;tr style="height: 15pt;" height="20"&gt;   &lt;td style="border: medium none ; padding: 0px; height: 15pt; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;" height="20"&gt;   &lt;b&gt;GC 40&lt;/b&gt;&lt;/td&gt;   &lt;td style="border: medium none ; padding: 0px; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;"&gt;                                      71 &lt;/td&gt;   &lt;td style="border: medium none ; padding: 0px; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;"&gt;                                117.5 &lt;/td&gt;   &lt;td style="border: medium none ; padding: 0px; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;"&gt;                              14.1 &lt;/td&gt;  &lt;/tr&gt;  &lt;tr style="height: 15pt;" height="20"&gt;   &lt;td style="border: medium none ; padding: 0px; height: 15pt; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;" height="20"&gt;   &lt;b&gt;GC 100&lt;/b&gt;&lt;/td&gt;   &lt;td style="border: medium none ; padding: 0px; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;"&gt;                                      71 &lt;/td&gt;   &lt;td style="border: medium none ; padding: 0px; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;"&gt;                                115.6 &lt;/td&gt;   &lt;td style="border: medium none ; padding: 0px; color: black; font-size: 11pt; font-weight: 400; font-style: normal; text-decoration: none; font-family: Calibri,sans-serif; vertical-align: bottom; white-space: nowrap;"&gt;&lt;br /&gt;&lt;/td&gt;  &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_g2tNCh4si2M/R5RhgJmh_mI/AAAAAAAAAAw/Dvuh98k0kPA/s1600-h/UnitTest.gif"&gt;&lt;img style="cursor: pointer;" src="http://bp3.blogger.com/_g2tNCh4si2M/R5RhgJmh_mI/AAAAAAAAAAw/Dvuh98k0kPA/s400/UnitTest.gif" alt="" id="BLOGGER_PHOTO_ID_5157854678207299170" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Conclusion&lt;/span&gt;&lt;br /&gt;&lt;s&gt;Based on these results, I would have to say that my comment &lt;span style="font-style: italic;"&gt;"A well written and tuned garbage collector can be faster than manual allocation."&lt;/span&gt; is correct.  Given sufficient heap space, the gc version is faster in some tests, and 1% slower in others.&lt;/s&gt;&lt;br /&gt;&lt;br /&gt;Le me restate my conclusion as the initial one is not well worded in terms of what I intended to say.  A better conclusion would be "It is possible for a garbage collected application to run at a speed similar to that of an application using manual deallocation".  Or alternately, "adding a gc to an application doesn't automatically make it incredibly slow".&lt;br /&gt;&lt;br /&gt;The gc performance could probably be improved further by surfacing the gc tuning options, improving the delphi wrapper and using a later version of the GC. The unit tests could also be sped up by removing the now redundant frees, destructors and try ... finally blocks&lt;br /&gt;&lt;br /&gt;The Boehm GC used is an early version 6 (6.2 or so).  Version 7 is available from cvs.  V7.1 should be released soon.&lt;br /&gt;&lt;br /&gt;There are downsides to using a gc, such as increased memory use.  It is not  appropriate for all applications, especially those with memory constraints.  However speed does not appear to be one of those downsides.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Update&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In response to a query, yes the garbage collector is running, and collecting the objects.  After the initial run (which may increase the heap), the heap size remains static no matter how many times I repeat the test (any of the tests).&lt;br /&gt;&lt;br /&gt;I also repeated the FastMM test removing the testObj.Free; line.&lt;br /&gt;&lt;br /&gt;It "completed" in 35 seconds.  By completed, I mean "used up 1.3gig of free mem, all my 4gig page file and then threw an "out of memory" exception.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Reference&lt;/span&gt;&lt;br /&gt;&lt;a href="http://www.hpl.hp.com/hosted/linux/mail-archives/gc/2008-January/002073.html"&gt;GC Mailing list: Are there any benchmarks comparing the speed of gc v non gc&lt;/a&gt;&lt;br /&gt;&lt;a href="http://codecentral.codegear.com/Item/21646"&gt; Garbage collector for Delphi&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/"&gt;Boehm GC&lt;/a&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Garbage_collection_%28computer_science%29"&gt;Wikipedia article&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="file:///C:/Users/sean/AppData/Local/Temp/moz-screenshot-2.jpg" alt="" /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-3435974333306538379?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/3435974333306538379/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=3435974333306538379' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/3435974333306538379'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/3435974333306538379'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2008/01/garbage-collection-performance-test.html' title='Garbage collection: Performance test'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp2.blogger.com/_g2tNCh4si2M/R5RZo5mh_lI/AAAAAAAAAAo/KWKezQyXTdY/s72-c/BenchMark.gif' height='72' width='72'/><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-4156821991309802928</id><published>2008-01-18T12:21:00.000+13:00</published><updated>2008-01-18T13:19:05.255+13:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='delphi'/><category scheme='http://www.blogger.com/atom/ns#' term='garbage collection'/><title type='text'>Garbage collection: Follow up</title><content type='html'>Given some of the feedback on my previous post, I thought a follow up would be in order&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Performance&lt;/span&gt;&lt;br /&gt;One of the most contentious points was my comment that "A well written and tuned garbage collector can be faster than manual allocation".  I will cover this in a separate post as it needs more than a couple of lines.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Why would you want to use a GC in delphi&lt;/span&gt;&lt;br /&gt;I will cover this in a separate post as well.  There is probably little gain in just adding a gc to an existing delphi app (unless it's leaky, but we don't write apps like that).  If you are writing a new app based around having a gc in place, then you can do things differently.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Clarifications&lt;/span&gt;&lt;br /&gt;Once of the original quotes referred to objects referencing each other not being released.  I read this as talking about cyclic references.  That is a problem with simple reference counting, but not with a tracing (ie mark and sweep) gc such as used by Boehm, .net and java (1). &lt;br /&gt;&lt;br /&gt;A gc is not a silver bullet, nor will it catch all memory leaks.  I am not suggesting that it will.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Corrections&lt;/span&gt;&lt;br /&gt;One point I forgot to mention.  Some gc algorithms will allocate extra memory for flags, counts etc (1).  This can push up the memory use compared to manual allocation.  However Fast mm 4 (2) also allocations a 32 bit flag ahead of every memory block so it is probably a wash.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Fast mm&lt;/span&gt;&lt;br /&gt;Fast mm will not catch all memory leaks.  It will catch memory that hasn't been freed when the application exits (2) which is not the same thing. &lt;br /&gt;&lt;br /&gt;If you have poor testing coverage, then the untested code can have memory leaks. &lt;br /&gt;Fast mm will not catch objects freed on application shutdown (ie forms owned by the application).  A gc won't catch this either.&lt;br /&gt;&lt;br /&gt;Fast mm will help with double frees, but it won't help with a/v errors (unless I am missing something, it certainly hasn't helped me).  A gc will help with both of those (1).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;References&lt;/span&gt;&lt;br /&gt;1 The &lt;a href="http://en.wikipedia.org/wiki/Garbage_collection_%28computer_science%29"&gt;wikipedia article on Garbage collection&lt;/a&gt; provides a lot of the background.&lt;br /&gt;2 Fast mm details are taken from &lt;a href="http://dn.codegear.com/article/33416"&gt;http://dn.codegear.com/article/33416&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;"However most Delphi memory managers request large chucks of memory from windows  and then parcel it out to the app on request,"  See (2) and &lt;a href="http://www.nexusdb.com/showpage.asp?Id=129"&gt;Nexus MM&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The quotes in the original article are taken from the newsgroup thread "&lt;a href="http://preview.tinyurl.com/2c6sq9"&gt;Garbage collection&lt;/a&gt;"&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-4156821991309802928?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/4156821991309802928/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=4156821991309802928' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/4156821991309802928'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/4156821991309802928'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2008/01/garbage-collection-follow-up.html' title='Garbage collection: Follow up'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7028181408582795486.post-2652174325692349900</id><published>2008-01-17T12:33:00.000+13:00</published><updated>2008-01-17T16:59:37.568+13:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='delphi'/><category scheme='http://www.blogger.com/atom/ns#' term='garbage collection'/><title type='text'>Garbage collection in Delphi Win 32: Why and how to do it</title><content type='html'>I got drawn into a newsgroup thread last month (&lt;a href="http://preview.tinyurl.com/2a6o5k"&gt;Delphi and XCode&lt;/a&gt;) regarding Delphi and x code.  I posted on the existence of a Garbage collector for Delphi  (&lt;a href="http://codecentral.codegear.com/Item/21646"&gt;http://codecentral.codegear.com/Item/21646&lt;/a&gt;) and spent several days in ongoing discussion.  Another recent thread is at &lt;a href="http://preview.tinyurl.com/2c6sq9"&gt;Garbage Collection&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;This posting is a summary of my views of the subject.  I spent 3 years as a fulltime C# programmer (and about 14 as a Delphi programmer) so I have a reasonable amount of experience and without a GC.  Based on some of the comments I have been reading, there are a lot of people with more opinion than experience in the newsgroups (no surprises there).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Note: When I refer to Delphi, I mean Delphi win 32.  When referring to Delphi.net, I do explicitly.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In general, the debate over garbage collection is already over.  I am unaware of any recent language that doesn’t have gc built in.  There is even a proposal before the c++ standards board to have a gc in c++.  In other words, get used to the idea.&lt;br /&gt;&lt;br /&gt;There seems to be a certain amount of dislike/distrust  of garbage collection amongst a number of people.  So far I have seen comments about laziness and incompetence, spurious  analogies to automatic cars and a fair amount of 'I know how to free  memory (usually) therefore it must be a good thing'.&lt;br /&gt;&lt;br /&gt;Most of the comments are more rhetorical than reasoned arguments:&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span&gt;&lt;span style="font-style: italic;"&gt;"Garbage collection leads to sloppy, bloated, inefficient code", Any number of comments on laziness and incompentance&lt;/span&gt;: Garbage collection is not about incompetence or laziness. It is perfectly possible to be competent and still prefer a GC.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span&gt;&lt;span style="font-style: italic;"&gt;"destructor calls have to be replaced by strict nil'ing of references"&lt;/span&gt;: You typically don't need to set objects to nil, although there are some cases where you would want to.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span&gt;&lt;span style="font-style: italic;"&gt;"There's also a problem with objects referencing each other which prevents the items releasing"&lt;/span&gt;: Not with any recent garbage collector.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span&gt;&lt;span style="font-style: italic;"&gt;"It's inefficient, it slow, and its unacceptable."&lt;/span&gt;: Again, not with any recent GC. In many cases a GC app is faster than non-gced.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;What is garbage collection?&lt;/span&gt;&lt;br /&gt;Garbage collection (GC) is the automatic release of unused memory and objects.&lt;br /&gt;&lt;br /&gt;E.g.&lt;br /&gt;&lt;br /&gt;MyStrings:= TStringlist.Create;&lt;br /&gt;// try&lt;br /&gt;do stuff here&lt;br /&gt;// finally&lt;br /&gt;//   MyStrings.Free; // no longer required&lt;br /&gt;// end;&lt;br /&gt;&lt;br /&gt;The try..finally and Free are no longer required as objects are released when (sometime after) they are no longer referenced.&lt;br /&gt;&lt;br /&gt;See &lt;a href="http://en.wikipedia.org/wiki/Garbage_collection_%28computer_science%29"&gt;wikipedia&lt;/a&gt; for more info than you ever needed on the subject.&lt;br /&gt;&lt;br /&gt;Garbage collection does not release resources (database connections, windows handles, etc).  These should be released manually.&lt;br /&gt;&lt;br /&gt;Strings, dynamic arrays and interfaces are already garbage collected in Delphi , and virtually everything is in Delphi.net.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Why use garbage collection?&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Fewer memory leaks:  By reducing the need for manually freeing memory, a gc significantly reduces the scope for memory leaks.  It is still possible to leak memory, but much harder.&lt;/li&gt;&lt;li&gt;Less code:  I performed a naive analysis on my most recent project by removing most .Free calls and the supporting destructors and try … finally blocks.  The result was about 4% fewer lines of code.&lt;/li&gt;&lt;li&gt;Better code:  In a non gc language, you end up with a number of idioms and practices to guard against memory leaks.  Delphi has several of these.&lt;br /&gt;Eg:&lt;br /&gt;It is rare to return an object from a function.  Typically you would create an object and then pass it to a procedure to be modified.&lt;br /&gt;The use of assign rather than :=&lt;br /&gt;The use of Owner, Owned and the like to solve object destruction problems)&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;There are some problems that it is difficult to solve without a GC.  Linq is often given as an example.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;What are the disadvantages of a garbage collector?&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Memory use:  A non gc app can free memory as soon as it is no longer required.  A gc however will only free memory once it is satisfied that it is not being used, which could be some considerable time later.  Typically the gc will only collect objects when it is feeling some memory pressure.  Therefore a non gc app can use less memory than a gc app.  However most Delphi memory managers request large chucks of memory from windows and then parcel it out to the app on request, so this disadvantage is largely theoretical.&lt;/li&gt;&lt;li&gt;Speed: A well written and tuned garbage collector can be faster than manual allocation.  Unfortunately there is no gc tuned for Delphi.  The only available gc is slightly slower than the default memory manager.&lt;/li&gt;&lt;li&gt;Reliance on a gc: Code that is written to take advantage of a gc cannot be readily run without a gc.  If your code must work in standard Delphi, then it must be programmed accordingly and not rely on the ex.&lt;/li&gt;&lt;li&gt;Non deterministic finalisation: With a gc, you have little control over when the object is removed from memory.  Even when it is removed, destroy is not called unless you have implemented a finalizer.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Why not use Delphi.net&lt;/span&gt;&lt;br /&gt;I spent 3 years as a c# and c++ programmer.  If I wanted to use .net, I would use c# and have access to all the latest toys such as linq.&lt;br /&gt;&lt;br /&gt;The main drawback with .net is the need to distribute a very large runtime library with the application.  This may not be a problem with web apps or internal applications, but it can be a large issue with shareware.&lt;br /&gt;&lt;br /&gt;A second drawback specific to delphi.net is that your code may end up being used by Delphi win 32.  As a result, the recommended approach is to program as if the gc did not exist.  That is, to include the .Free calls, the try … finally blocks and the destructors.  You end up with the all of the drawbacks of a gc, without the advantages.&lt;br /&gt;&lt;br /&gt;A third drawback for me is that many of the libraries and controls I use are not available in Delphi.net.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;What about other resources?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If your object holds other resources such as windows handles, database connections etc then you still need to release those.  Depending on the object you can do this with .Free, .Close, .Disconnect or similar.  .Free will always work the object will be disposed of although the memory won't be released until the gc gets around to it.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;How do you use a Garbage Collector in Delphi win32?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The Delphi memory manager is designed to be easily replaceable.  A garbage collected memory manger is available from &lt;a href="http://codecentral.codegear.com/Item/21646"&gt;http://codecentral.codegear.com/Item/21646&lt;/a&gt;.  This is written by Barry Kelly and is a thin wrapper around the &lt;a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/"&gt;Boehm GC&lt;/a&gt; library.  I have made some changes to make it work better.  If there is any interest, I will post the code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7028181408582795486-2652174325692349900?l=sourceitsoftware.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourceitsoftware.blogspot.com/feeds/2652174325692349900/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7028181408582795486&amp;postID=2652174325692349900' title='19 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/2652174325692349900'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7028181408582795486/posts/default/2652174325692349900'/><link rel='alternate' type='text/html' href='http://sourceitsoftware.blogspot.com/2008/01/garbage-collection-in-delphi-win-32-why.html' title='Garbage collection in Delphi Win 32: Why and how to do it'/><author><name>Sean</name><uri>http://www.blogger.com/profile/09419639577416328173</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>19</thr:total></entry></feed>
