<?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-7543977687602745925</id><updated>2011-12-14T09:58:48.564-08:00</updated><category term='logging'/><category term='GPU'/><category term='Python'/><category term='Windows Mobile'/><category term='Twitter'/><category term='Microsoft'/><category term='multi-threaded'/><category term='MVC'/><category term='PsTools'/><category term='Quentin Zervaas'/><category term='.Net'/><category term='Expression Blend'/><category term='rounding errors'/><category term='Plink'/><category term='Windows'/><category term='GDI'/><category term='GNU'/><category term='regular-expression'/><category term='validation'/><category term='Programming'/><category term='XAML'/><category term='C++'/><category term='timer'/><category term='CPU'/><category term='grep'/><category term='Delphi'/><category term='Campaign Cartographer'/><category term='Quakk'/><category term='Hudson'/><category term='physics'/><category term='XHTML'/><category term='Flash Drive'/><category term='SmartFoxServer'/><category term='personality testing'/><category term='CC3'/><category term='Continuous Integration'/><category term='Philadelphia'/><category term='Entrepreneur'/><category term='multi-boot'/><category term='SGML'/><category term='findutils'/><category term='Developer Tool Kit'/><category term='MediaWiki'/><category term='P/Involk'/><category term='XML'/><category term='backups'/><category term='Zend'/><category term='Java'/><category term='IIS'/><category term='Widgets'/><category term='C#'/><category term='PHP'/><category term='Netgear'/><category term='Pscp'/><category term='iPhone'/><category term='Alienware'/><category term='PostgreSQL'/><category term='VMware'/><category term='Corel Draw'/><category term='SysInternals'/><category term='log'/><category term='HTML'/><category term='SmartFox'/><category term='mathematics'/><category term='marketing'/><category term='log4net'/><category term='certificate'/><category term='Putty'/><category term='Ryzing'/><category term='6.5'/><category term='System Commander'/><category term='Wiki'/><category term='TortoiseSVN'/><category term='SVN'/><category term='Illustrator'/><category term='TENG'/><category term='Silverlight'/><title type='text'>Jeff's Thoughts</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://jeffmcarthur.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://jeffmcarthur.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Jeffrey McArthur</name><uri>http://www.blogger.com/profile/08114179926352904007</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_Qg-uhnOHTis/STbiKa5SGxI/AAAAAAAAAAM/xPpYa0jlVDM/S220/Jeff+Head.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>30</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7543977687602745925.post-7006532752547963870</id><published>2010-09-08T18:58:00.001-07:00</published><updated>2010-09-08T19:00:32.322-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Wiki'/><category scheme='http://www.blogger.com/atom/ns#' term='TortoiseSVN'/><category scheme='http://www.blogger.com/atom/ns#' term='MediaWiki'/><category scheme='http://www.blogger.com/atom/ns#' term='Flash Drive'/><category scheme='http://www.blogger.com/atom/ns#' term='SVN'/><title type='text'>Joys of Removable Version of MediaWiki and SVN</title><content type='html'>&lt;span xmlns=''&gt;&lt;p&gt;I have a variety of flash memory devices. I picked a two-Gigabyte device to put a copy of MediaWiki and SVN. I now can access my personal wiki everywhere I go.
&lt;/p&gt;&lt;h2&gt;Wiki on a Stick
&lt;/h2&gt;&lt;p&gt;&lt;a href='http://www.chsoftware.net'&gt;CH Software&lt;/a&gt; created MoWeS, an entire WAMP (Windows, Apache, MySQL, and PHP) stack that run without the need to install anything. MoWeS allow selecting which version of Apache, PHP, and MySQL. MediaWiki is an additional option along with other great options like ImageMagick, TYPO3, and SugarCRM. MediaWiki provides an &lt;a href='http://www.mediawiki.org/wiki/Manual:Installing_on_WOS_Portable_(Windows)'&gt;installation page&lt;/a&gt;. The instructions are not quite right. Download the packages from CH Software then run moves.exe. That unpacks the files.
&lt;/p&gt;&lt;h2&gt;SVN on a Stick
&lt;/h2&gt;&lt;p&gt;I use &lt;a href='http://tortoisesvn.tigris.org/'&gt;TortoiseSVN&lt;/a&gt;. This integrates SVN with Windows Explorer. TortoiseSVN has the option to create a repository by just right clicking on a directory. This makes it simple to create an SVN repository on a memory stick.
&lt;/p&gt;&lt;h2&gt;Performance
&lt;/h2&gt;&lt;p&gt;Performance of SVN is a slow on my two-Gigabyte flash drive. The advantage of taking both my personal wiki and an SVN repository with me anywhere outweighs the performance issues.
&lt;/p&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7543977687602745925-7006532752547963870?l=jeffmcarthur.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jeffmcarthur.blogspot.com/feeds/7006532752547963870/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7543977687602745925&amp;postID=7006532752547963870' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/7006532752547963870'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/7006532752547963870'/><link rel='alternate' type='text/html' href='http://jeffmcarthur.blogspot.com/2010/09/joys-of-removable-version-of-mediawiki.html' title='Joys of Removable Version of MediaWiki and SVN'/><author><name>Jeffrey McArthur</name><uri>http://www.blogger.com/profile/08114179926352904007</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_Qg-uhnOHTis/STbiKa5SGxI/AAAAAAAAAAM/xPpYa0jlVDM/S220/Jeff+Head.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7543977687602745925.post-4349455782904680138</id><published>2010-09-05T13:38:00.001-07:00</published><updated>2010-09-05T13:38:35.148-07:00</updated><title type='text'>ASP MVC 2 – NUnit based unit test project template For Visual Studio 2008</title><content type='html'>&lt;span xmlns=''&gt;&lt;p&gt;Piotr Kwapin wrote an article about creating a &lt;a href='http://www.geekbeing.com/2010/07/21/asp-mvc-2-nunit-based-unit-test-project-template/trackback/'&gt;NUnit based unit test project template for ASP MVC2&lt;/a&gt; for Visual Studio 2010. I am still using Visual Studio 2008. This was an interesting learning experience. I never previously delved into project templates.
&lt;/p&gt;&lt;p&gt;Piotr Kwapin mentioned this would work with Visual Studio 2008 but did not elaborate. I was able to get it working after some rather scary moments.
&lt;/p&gt;&lt;h2&gt;Download the Template
&lt;/h2&gt;&lt;p&gt;The first step is to download the &lt;a href='http://www.jeffreymcarthur.com/NUnitTestVS9.zip'&gt;template&lt;/a&gt; updated for Visual Studio 2008. The template is a zip file containing the following.
&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;div&gt;&lt;strong&gt;Controllers
&lt;/strong&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;AccountControllerTest.cs
&lt;/li&gt;&lt;li&gt;HomeControllerTest.cs
&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;div&gt;&lt;strong&gt;Properties
&lt;/strong&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;AssemblyInfo.cs
&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;App.config
&lt;/li&gt;&lt;li&gt;MvcApplicationTest.csproj
&lt;/li&gt;&lt;li&gt;MvcWebApplicationNUnitBasedTestProjectTemplate.cs.vstemplate
&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Put the template file in the template directory. On a PC running a 64-bit operating system, this directory is located here. Do not unzip or extract files from the zip.
&lt;/p&gt;&lt;p&gt;&lt;pre&gt;&lt;code&gt;c:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\ProjectTemplates\CSharp\Test\
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;&lt;h2&gt;Download the Registration File
&lt;/h2&gt;&lt;p&gt;The next step is downloading the updated &lt;a href='http://www.jeffreymcarthur.com/NUnit-VS9-Test-Reg.zip'&gt;registration file&lt;/a&gt;. Extract the registration file and execute it. Windows will issues several warning and confirmations about running the file.
&lt;/p&gt;&lt;h2&gt;Running Devenv Setup
&lt;/h2&gt;&lt;p&gt;Piotr Kwapin did not document the last step as completely. You need to open up a command line as administrator that has the path setup to run devenv.exe. On Windows 7, select Start, All Programs, Visual Studio 2008, and then Visual Studio Tools.
&lt;/p&gt;&lt;p&gt;
 &lt;/p&gt;&lt;p&gt;Right click on Visual Studio 2008 Command Prompt and select Run as administrator. Enter the following command.
&lt;/p&gt;&lt;p&gt;&lt;pre&gt;&lt;code&gt;devenv /setup
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;
 &lt;/p&gt;&lt;p&gt;The first time I did that, Visual Studio 2008 forgot about all its templates. I suggest running the command a couple of times. I ran the command around a dozen times as I made minor changes to the files to get them to work with Visual Studio 2008. I documented the changes I made to the files below.
&lt;/p&gt;&lt;h2&gt;Changes to the VSTemplate File
&lt;/h2&gt;&lt;p&gt;I changed the version number for Microsoft Visual Studio from 10.0.0.0 to 9.0.0.0. Below is the updated line.
&lt;/p&gt;&lt;p&gt;&lt;pre&gt;&lt;code&gt;&amp;lt;Assembly&amp;gt;Microsoft.VisualStudio.Web.Mvc.2.0, Version=9.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35&amp;lt;/Assembly&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;&lt;h2&gt;Changes to the CSProj file
&lt;/h2&gt;&lt;p&gt;I changed the tools version from 4.0 to 3.5. Below is the updated line.
&lt;/p&gt;&lt;p&gt;&lt;pre&gt;&lt;code&gt;&amp;lt;Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;&lt;h2&gt;Changes to the Registration File
&lt;/h2&gt;&lt;p&gt;I made two changes to the registration file. The first is a change to the name of the template. I compressed the template files into NUnitTestVS9.zip. The second change is the change of the HKEY to Visual Studio 2008. The two lines below show the changes.
&lt;/p&gt;&lt;p&gt;&lt;pre&gt;&lt;code&gt;[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\9.0\MVC2\TestProjectTemplates\NUnit\C#]
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;&lt;pre&gt;&lt;code&gt;"Template"="NUnitTestVS9.zip"
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;&lt;h2&gt;A New ASP.NET MVC 2 Web Application
&lt;/h2&gt;&lt;p&gt;Creating a new ASP.Net MVC 2 Web Application in Visual Studio 2008 creates both the project and allows creating a NUnit test project. Below is an example in Solution Explorer.
&lt;/p&gt;&lt;p&gt;
 &lt;/p&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7543977687602745925-4349455782904680138?l=jeffmcarthur.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jeffmcarthur.blogspot.com/feeds/4349455782904680138/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7543977687602745925&amp;postID=4349455782904680138' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/4349455782904680138'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/4349455782904680138'/><link rel='alternate' type='text/html' href='http://jeffmcarthur.blogspot.com/2010/09/asp-mvc-2-nunit-based-unit-test-project.html' title='ASP MVC 2 – NUnit based unit test project template For Visual Studio 2008'/><author><name>Jeffrey McArthur</name><uri>http://www.blogger.com/profile/08114179926352904007</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_Qg-uhnOHTis/STbiKa5SGxI/AAAAAAAAAAM/xPpYa0jlVDM/S220/Jeff+Head.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7543977687602745925.post-3560201044402691130</id><published>2010-08-11T15:13:00.001-07:00</published><updated>2010-08-11T15:17:30.449-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SmartFoxServer'/><category scheme='http://www.blogger.com/atom/ns#' term='Putty'/><category scheme='http://www.blogger.com/atom/ns#' term='SysInternals'/><category scheme='http://www.blogger.com/atom/ns#' term='Pscp'/><category scheme='http://www.blogger.com/atom/ns#' term='SmartFox'/><category scheme='http://www.blogger.com/atom/ns#' term='Hudson'/><category scheme='http://www.blogger.com/atom/ns#' term='Plink'/><category scheme='http://www.blogger.com/atom/ns#' term='PsTools'/><title type='text'>Hudson, SmartFoxServer, Plink, and Running Command as Local System Account</title><content type='html'>&lt;span xmlns=''&gt;&lt;p&gt;&lt;a href='http://www.smartfoxserver.com/'&gt;SmartFoxServer&lt;/a&gt; is a platform for developing massively multi-user applications. SmartFoxServer is a Java application and supports calling extensions in Java, Action Script, and Python. As a Java application, SmartFoxServer runs well on Windows or Linux. 
&lt;/p&gt;&lt;p&gt;&lt;a href='http://www.ryzing.com/'&gt;Ryzing&lt;/a&gt; tested running SmartFoxServer on Windows and Linux. We ended up using an &lt;a href='http://aws.amazon.com/ec2/'&gt;Amazon EC2&lt;/a&gt; instance running &lt;a href='http://www.ubuntu.com/'&gt;Ubuntu Linux&lt;/a&gt; to host the SmartFoxServer. SmartFoxServer interprets the Action Script extensions. You cannot compile the extensions. SmartFoxServer caches all the Action Script extensions. The server will not reload the extensions if they change. SmartFox developed an admin Flash client application to manage the SmartFoxServer. You can use the Flash admin client to force extensions to reload.
&lt;/p&gt;&lt;p&gt;I designed the Hudson build process at Ryzing to push the SmartFoxServer extensions to the Linux server. Fortunately, SmartFox implemented a set of command line tools in addition to the Flash client. The process of pushing the extensions to the server is a simple task in Hudson.
&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Extract the source from SVN&lt;/li&gt;&lt;li&gt;Rename some files to match the destination server&lt;/li&gt;&lt;li&gt;Push the sources to the server using PSCP&lt;/li&gt;&lt;li&gt;Reset the SmartFoxServer&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&lt;a href='http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html'&gt;Pscp&lt;/a&gt; is an implementation of scp or secure copy that runs on Windows. Pscp is one of the tools included with Putty. The process should be simple. However, there is a problem. The first time Putty, Pscp, or Plink connects to a server, they cache the host key in the registry. You get something like the following.&lt;/p&gt;&lt;p&gt;&lt;pre&gt;&lt;code&gt;The server's host key is not cached in the registry. You
have no guarantee that the server is the computer you
think it is.
The server's rsa2 key fingerprint is:
ssh-rsa 2048 hh:hh:hh:hh:hh:hh:hh:hh:hh:hh:hh:hh:hh:hh:hh:hh
If you trust this host, enter "y" to add the key to
PuTTY's cache and carry on connecting.
If you want to carry on connecting just once, without
adding the key to the cache, enter "n".
If you do not trust this host, press Return to abandon the
connection.
Store key in cache? (y/n)&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;Putty, Pscp, and Plink support a batch option. With the batch option, if the host key is not in the registry cache Putty, Pscp, and Plink automatically exit. The problem is the registry cache is user specific. This causes a problem with Hudson installed as a service running on Windows. When installed as a service, Hudson runs as the Local System Account. Running Pscp as a task in a Hudson project will lock up waiting for the user to press "Y" or "N". If you add the option to run as batch, the command will always fail.&lt;/p&gt;&lt;p&gt;How do you install the host key in the registry for the Local System Account? I am sure there are other solutions. The one I found was to open a command prompt as the Local System Account. Unfortunately, this is not as simple as it sounds. I finally found the solution here: &lt;a href='http://johnnycoder.com/blog/2008/11/10/run-cmdexe-as-local-system-account/'&gt;http://johnnycoder.com/blog/2008/11/10/run-cmdexe-as-local-system-account/&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;The solution is to use psexec.exe, which is part of &lt;a href='http://download.sysinternals.com/Files/PsTools.zip'&gt;PsTools&lt;/a&gt; from &lt;a href='http://sysinternals.com/'&gt;SysInternals&lt;/a&gt;. Microsoft acquired Sysinternals in July 2006. The following opens a command prompt as the Local System Account.&lt;/p&gt;&lt;p&gt;&lt;pre&gt;&lt;code&gt;psexec -i -s cmd.exe&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;After the command window opens, attempt to connect via Pscp or Plink. Answer "Y" to "Store key in cache?"&lt;/p&gt;&lt;p&gt;Now Hudson can copy the files from SVN to the Linux server and restart SmartFoxServer.&lt;/p&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7543977687602745925-3560201044402691130?l=jeffmcarthur.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jeffmcarthur.blogspot.com/feeds/3560201044402691130/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7543977687602745925&amp;postID=3560201044402691130' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/3560201044402691130'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/3560201044402691130'/><link rel='alternate' type='text/html' href='http://jeffmcarthur.blogspot.com/2010/08/hudson-smartfoxserver-plink-and-running.html' title='Hudson, SmartFoxServer, Plink, and Running Command as Local System Account'/><author><name>Jeffrey McArthur</name><uri>http://www.blogger.com/profile/08114179926352904007</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_Qg-uhnOHTis/STbiKa5SGxI/AAAAAAAAAAM/xPpYa0jlVDM/S220/Jeff+Head.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7543977687602745925.post-6499376040753641575</id><published>2010-08-10T16:44:00.001-07:00</published><updated>2010-08-10T16:47:18.582-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ryzing'/><category scheme='http://www.blogger.com/atom/ns#' term='Hudson'/><category scheme='http://www.blogger.com/atom/ns#' term='PostgreSQL'/><category scheme='http://www.blogger.com/atom/ns#' term='backups'/><category scheme='http://www.blogger.com/atom/ns#' term='Continuous Integration'/><title type='text'>Using Hudson for Unusual Tasks</title><content type='html'>&lt;span xmlns=''&gt;&lt;p&gt;Martin Fowler wrote, "Continuous Integration is a software development practice where members of a team integrate their work frequently, usually each person integrates at least daily - leading to multiple integrations per day. Each integration is verified by an automated build (including test) to detect integration errors as quickly as possible. Many teams find that this approach leads to significantly reduced integration problems and allows a team to develop cohesive software more rapidly." (&lt;a href='http://martinfowler.com/articles/continuousIntegration.html'&gt;http://martinfowler.com/articles/continuousIntegration.html&lt;/a&gt;)
&lt;/p&gt;&lt;p&gt;Hudson is a continuous integration solution. "In a nutshell, Hudson provides an easy-to-use so-called continuous integration system, making it easier for developers to integrate changes to the project, and making it easier for users to obtain a fresh build." (&lt;a href='http://wiki.hudson-ci.org/display/HUDSON/Meet+Hudson'&gt;http://wiki.hudson-ci.org/display/HUDSON/Meet+Hudson&lt;/a&gt;)
&lt;/p&gt;&lt;p&gt;I found somewhat unusual uses for Hudson.
&lt;/p&gt;&lt;p&gt;&lt;a href='http://www.ryzing.com/'&gt;Ryzing&lt;/a&gt; follows a standard development setup with a set of servers (or chain) for each stage of development: Alpha, Quality Assurance (or QA), and Production. We chose the &lt;a href='http://aws.amazon.com/ec2/'&gt;Amazon Cloud&lt;/a&gt; to host the servers. Three chains mean three separate databases running on three separate database servers. I firmly believe in automating routine tasks. A daily backup is definitely a routine task. My solution to automating the backups was to use our Hudson server.
&lt;/p&gt;&lt;p&gt;The Ryzing applications use PostgreSQL as the database server. I installed the full PostgreSQL tool set on the Windows 2008 server dedicated to running Hudson (&lt;a href='http://www.postgresql.org/download/windows'&gt;http://www.postgresql.org/download/windows&lt;/a&gt;). I made sure that both the Windows firewall and the Amazon security zones allowed the build server to talk to the database servers in the Alpha, QA, and Production chains.
&lt;/p&gt;&lt;p&gt;The project in Hudson is simple. The build process uses a Windows batch command. Below are the commands I used.
&lt;/p&gt;&lt;p&gt;&lt;pre&gt;&lt;code&gt;SET PGPASSWORD=PASSWORD
"C:\Program Files\PostgreSQL\8.4\bin\pg_dump.exe" --no-password --file=DATABASENAME.backup --format=c --host=HOSTNAME --port=HOSTPORT -U USERNAME DATABASENAME
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;You will need to set the appropriate password, database name, host name, user name, and host port. I checked a Post-Build action to Archive the Artifacts telling Hudson to archive DATABASENAME.backup. I selected the build trigger of building periodically. Each morning the build server runs the backup on each database.
&lt;/p&gt;&lt;p&gt;Hudson provides a convenient place to store the database backups along with all our software builds.
&lt;/p&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7543977687602745925-6499376040753641575?l=jeffmcarthur.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jeffmcarthur.blogspot.com/feeds/6499376040753641575/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7543977687602745925&amp;postID=6499376040753641575' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/6499376040753641575'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/6499376040753641575'/><link rel='alternate' type='text/html' href='http://jeffmcarthur.blogspot.com/2010/08/using-hudson-for-unusual-tasks.html' title='Using Hudson for Unusual Tasks'/><author><name>Jeffrey McArthur</name><uri>http://www.blogger.com/profile/08114179926352904007</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_Qg-uhnOHTis/STbiKa5SGxI/AAAAAAAAAAM/xPpYa0jlVDM/S220/Jeff+Head.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7543977687602745925.post-5946182366319964544</id><published>2010-08-09T05:40:00.000-07:00</published><updated>2010-08-09T05:40:12.280-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MediaWiki'/><category scheme='http://www.blogger.com/atom/ns#' term='VMware'/><category scheme='http://www.blogger.com/atom/ns#' term='MVC'/><category scheme='http://www.blogger.com/atom/ns#' term='Netgear'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><title type='text'>The Joys of MeidaWiki and VMware</title><content type='html'>&lt;p&gt;Wikis are a useful tool. At my current position, I added a lot of technical documentation to the Wiki included in Trac. I wanted a wiki for my personal use. &lt;/p&gt;&lt;p&gt;I program in a variety of languages including C# and Java. Most of my recent work is in C#. I looked for a Wiki in C#. I found two. &lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;a href='http://sourceforge.net/projects/flexwiki/'&gt;FlexWiki&lt;/a&gt;     &lt;/li&gt;
&lt;li&gt;&lt;a href='http://tavaresstudios.com/Blog/page/ASPNET-MVC-Wiki-Sample.aspx'&gt;MiniWiki&lt;/a&gt;     &lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;I know there are others. Unfortunately, FlexWiki is abandoned. The source code is available. MiniWiki is just that a minimal Wiki. MiniWiki is interesting because it uses the ASP.Net MVC (version 1). &lt;/p&gt;&lt;p&gt;Both include unit tests. I am a bit of a fanatic about unit tests. In &lt;a href='http://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052'&gt;Working Effectively with Legacy Code&lt;/a&gt; Michael Feathers wrote, "Code without tests is bad code. It doesn't matter how well written it is; it doesn't matter how pretty or object-oriented or well-encapsulated it is. With tests, we can change the behavior of our code quickly and verifiably. Without them, we really don't know if our code is getting better or worse." &lt;/p&gt;&lt;p&gt;MiniWiki uses Moq. FlexWiki uses NUnit. Interesting neither include any logging framework.  &lt;/p&gt;&lt;p&gt;What I would like to do, if I ever find the time, is take the Wiki engine from FlexWiki and marry it with the MVC framework using MiniWiki as a start. That is a good long-term project. &lt;/p&gt;&lt;p&gt;In the short term, I need a personal wiki. The solution is MediaWiki and VMware. rPath created a MediaWiki appliance &lt;a href='http://wiki.rpath.com/wiki/Appliance:MediaWiki_Appliance'&gt;http://wiki.rpath.com/wiki/Appliance:MediaWiki_Appliance&lt;/a&gt;    &lt;/p&gt;&lt;p&gt;With the appliance I was up and running in minutes. &lt;/p&gt;&lt;p&gt;Last thing to do was to modify the .vmx file in the appliance to use a static MAC address.  Comment out the following lines. &lt;/p&gt;&lt;p&gt;&lt;pre&gt;&lt;code&gt;ethernet0.addressType = "generated"
ethernet0.generatedAddress = "00:0c:29:43:85:c8"
ethernet0.generatedAddressOffset = "0"
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;Then add something like the following. &lt;/p&gt;&lt;p&gt;&lt;pre&gt;&lt;code&gt;ethernet0.addressType = "static"
ethernet0.address = "00:50:56:00:00:04"
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;The MAC address you select depends on your network. I want a static MAC address to allow my Netgear router to assign the IP address. This gives the VM a fixed IP address inside my firewall. &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7543977687602745925-5946182366319964544?l=jeffmcarthur.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jeffmcarthur.blogspot.com/feeds/5946182366319964544/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7543977687602745925&amp;postID=5946182366319964544' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/5946182366319964544'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/5946182366319964544'/><link rel='alternate' type='text/html' href='http://jeffmcarthur.blogspot.com/2010/08/joys-of-meidawiki-and-vmware.html' title='The Joys of MeidaWiki and VMware'/><author><name>Jeffrey McArthur</name><uri>http://www.blogger.com/profile/08114179926352904007</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_Qg-uhnOHTis/STbiKa5SGxI/AAAAAAAAAAM/xPpYa0jlVDM/S220/Jeff+Head.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7543977687602745925.post-1226400155041290604</id><published>2010-08-08T20:16:00.000-07:00</published><updated>2010-08-08T20:43:51.226-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='VMware'/><category scheme='http://www.blogger.com/atom/ns#' term='GNU'/><category scheme='http://www.blogger.com/atom/ns#' term='grep'/><category scheme='http://www.blogger.com/atom/ns#' term='certificate'/><category scheme='http://www.blogger.com/atom/ns#' term='findutils'/><title type='text'>Fixing the Certificate Error Problem with VMware Server</title><content type='html'>&lt;p&gt;I use VMware server for many thing. For example, I own an older version of QuickBooks to bill for consulting projects. I use QuickBooks once a month to create invoices. For me, it is not worth the cost of upgrading to a new version of QuickBooks. I have a VM of Windows XP that runs my copy of QuickBooks.&lt;/p&gt;&lt;p&gt;One problem with VMware Server is Internet Explorer needs the certificate for the VMware Infrastructure Web Access program. Otherwise, you get a certificate error. VMware works fine if you ignore the error but it is easy to fix, once you find out how.&lt;/p&gt;&lt;p&gt;The biggest challenge is finding the certificate. I run Windows 7. The find for Windows is useless. It rarely finds any file I am looking for. A slower, but more reliable solution is the Gnu FindUtils for Windows. You can download a copy here:&lt;/p&gt;&lt;p&gt;&lt;a href="http://gnuwin32.sourceforge.net/packages/findutils.htm"&gt;http://gnuwin32.sourceforge.net/packages/findutils.htm&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Another useful utility is Gnu Grep for Windows. You can download a copy here:&lt;/p&gt;&lt;p&gt;&lt;a href="http://gnuwin32.sourceforge.net/packages/grep.htm"&gt;http://gnuwin32.sourceforge.net/packages/grep.htm&lt;/a&gt;&lt;/p&gt;&lt;p&gt;On Windows 6 (64 bit) the installation packages for FindUtils and Grep install the executables in C:\Program Files (x86)\GnuWin32\bin&lt;/p&gt;&lt;p&gt;The standard Windows command find is useless; but makes it impossible to execute the Gnu find. I rename Gnu's find.exe to gnufind.exe. I then add the location to the environment path variable. That allows running grep or gnufind from any command window.&lt;/p&gt;&lt;p&gt;Gnufind located the certificate use by VMware named rui.cert here C:\Program Files (x86)\VMware\VMware Server\SSL.&lt;/p&gt;&lt;p&gt;Once you know find the certificate, installing it is simple.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Open up Windows Explore and browse to the location of the certificate.&lt;/li&gt;&lt;li&gt;Double click on rui.cert&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The following dialog will display.&lt;/p&gt;
&lt;a href="http://2.bp.blogspot.com/_Qg-uhnOHTis/TF92HPf02_I/AAAAAAAAABo/esYTdw0uuAA/s1600/new-1.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 322px; height: 400px;" src="http://2.bp.blogspot.com/_Qg-uhnOHTis/TF92HPf02_I/AAAAAAAAABo/esYTdw0uuAA/s400/new-1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5503247136461216754" /&gt;&lt;/a&gt;
&lt;p&gt;Clicking on the Install Certificate brings up the wizard.&lt;/p&gt;
&lt;a href="http://2.bp.blogspot.com/_Qg-uhnOHTis/TF92n42ZlxI/AAAAAAAAABw/ht2ye4KvKow/s1600/new-3.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 363px;" src="http://2.bp.blogspot.com/_Qg-uhnOHTis/TF92n42ZlxI/AAAAAAAAABw/ht2ye4KvKow/s400/new-3.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5503247697317566226" /&gt;&lt;/a&gt;
&lt;p&gt;Select Place all certificates in the following store. Then click the Browse button.&lt;/p&gt;
&lt;a href="http://2.bp.blogspot.com/_Qg-uhnOHTis/TF93dQIX2vI/AAAAAAAAACA/KPQROPLe744/s1600/new-4.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 363px;" src="http://2.bp.blogspot.com/_Qg-uhnOHTis/TF93dQIX2vI/AAAAAAAAACA/KPQROPLe744/s400/new-4.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5503248614100032242" /&gt;&lt;/a&gt;
&lt;p&gt;Select Trusted Root Certificate Authorities.&lt;/p&gt;
&lt;a href="http://2.bp.blogspot.com/_Qg-uhnOHTis/TF93O5s9GfI/AAAAAAAAAB4/aulY3xIT8c0/s1600/new-5.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 295px; height: 269px;" src="http://2.bp.blogspot.com/_Qg-uhnOHTis/TF93O5s9GfI/AAAAAAAAAB4/aulY3xIT8c0/s400/new-5.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5503248367561284082" /&gt;&lt;/a&gt;
&lt;p&gt;Click OK&lt;/p&gt;
&lt;a href="http://4.bp.blogspot.com/_Qg-uhnOHTis/TF93_YGBXDI/AAAAAAAAACI/crpW7PbXxMA/s1600/new-6.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 363px;" src="http://4.bp.blogspot.com/_Qg-uhnOHTis/TF93_YGBXDI/AAAAAAAAACI/crpW7PbXxMA/s400/new-6.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5503249200353205298" /&gt;&lt;/a&gt;
&lt;p&gt;Click Next&lt;/p&gt;
&lt;a href="http://3.bp.blogspot.com/_Qg-uhnOHTis/TF94N37u96I/AAAAAAAAACQ/tZVFj2mHFG8/s1600/new-7.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 363px;" src="http://3.bp.blogspot.com/_Qg-uhnOHTis/TF94N37u96I/AAAAAAAAACQ/tZVFj2mHFG8/s400/new-7.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5503249449418160034" /&gt;&lt;/a&gt;
&lt;p&gt;Click Finish.&lt;/p&gt;&lt;p&gt;Close the browser. Now when you open up VMware server the cerficate problem is solved.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7543977687602745925-1226400155041290604?l=jeffmcarthur.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jeffmcarthur.blogspot.com/feeds/1226400155041290604/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7543977687602745925&amp;postID=1226400155041290604' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/1226400155041290604'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/1226400155041290604'/><link rel='alternate' type='text/html' href='http://jeffmcarthur.blogspot.com/2010/08/fixing-certificate-error-problem-with.html' title='Fixing the Certificate Error Problem with VMware Server'/><author><name>Jeffrey McArthur</name><uri>http://www.blogger.com/profile/08114179926352904007</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_Qg-uhnOHTis/STbiKa5SGxI/AAAAAAAAAAM/xPpYa0jlVDM/S220/Jeff+Head.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_Qg-uhnOHTis/TF92HPf02_I/AAAAAAAAABo/esYTdw0uuAA/s72-c/new-1.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7543977687602745925.post-2191292946442542723</id><published>2009-11-04T04:46:00.000-08:00</published><updated>2009-11-04T04:47:11.541-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='log'/><category scheme='http://www.blogger.com/atom/ns#' term='logging'/><category scheme='http://www.blogger.com/atom/ns#' term='timer'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='log4net'/><title type='text'>Log Timmer</title><content type='html'>&lt;p&gt;One common challenge in developing software is tuning performance. The application is running slow but you are not sure what is causing the problem. An approach to the debugging the problem is to use logging. This works, but you end up doing a lot of time arithmetic to determine how long it took some action to complete. Logging also adds many lines of code to the application muddling up the implementation and making it harder to read and understand. The solution is a class designed to time and log an event. I give credit to &lt;a href="http://www.linkedin.com/in/splichta"&gt;Scott Plichta&lt;/a&gt; for designing the architecture for the Log Timer.&lt;/p&gt;&lt;p&gt;Creating a log in C++ is easy. The constructor starts the timer and the destructor calculates the elapsed time and logs the results. This is a problem in Java. In Java, destructors are may not be called until the garbage collector runs. C# also uses garbage collection, but provides the IDisposable interface. IDisposable tells the garbage collector to dispose of the object as soon as possible. That means the timings provided by a log timer class in C# are not quite as accurate as the timing in a C++ log timer class.&lt;/p&gt;&lt;p&gt;How do you use the log timer class work in C#? The simplest method is just to place a "using" statement creating the log timer around the code you want to time:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;using (new LogTimer.LogTimer())&lt;br /&gt;{&lt;br /&gt;    // code you want to time&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Call that is a little more complicated allows passing in the custom message:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;using (new LogTimer.LogTimer("Deserialize time: "))&lt;br /&gt;{&lt;br /&gt;    // code you want to time&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The code above will always log. The LogTimer class has constructors that allow passing in the number of milliseconds for logging for each of the Log4Net levels. Below is an example passing in all the level thresholds:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;using (new LogTimer.LogTimer("DownloadImage GetReponse time: ", 5000, 3000, 2000, 100, 0))&lt;br /&gt;{&lt;br /&gt;    // code you want to time&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;There are several other constructors taking different number of thresholds.  Below is the implementation of the LogTimer class in C#.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Text;&lt;br /&gt;&lt;br /&gt;using log4net.Core;&lt;br /&gt;using System.Diagnostics;&lt;br /&gt;&lt;br /&gt;namespace LogTimer&lt;br /&gt;{&lt;br /&gt;    // based on:&lt;br /&gt;    // http://www.eggheadcafe.com/articles/20050625.asp&lt;br /&gt;    // http://www.codeproject.com/KB/cs/idispose.aspx&lt;br /&gt;&lt;br /&gt;    public class LogTimer : IDisposable&lt;br /&gt;    {&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Create a logger for use in this class&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        private static readonly log4net.ILog log = log4net.LogManager.GetLogger(typeof(LogTimer));&lt;br /&gt;&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Used by the destructor to avoid disposing twice&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        private bool disposed = false;&lt;br /&gt;&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Default message&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        private string msg = "LogTimer: ";&lt;br /&gt;&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Threashold in milliseconds before issuing a debug log&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        private readonly long debugCount = 0;&lt;br /&gt;&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Threashold in milliseconds before issuing a info log&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        private readonly long infoCount = 0;&lt;br /&gt;&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Threashold in milliseconds before issuing a warn log&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        private readonly long warnCount = 0;&lt;br /&gt;&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Threashold in milliseconds before issuing a error log&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        private readonly long errorCount = 0;&lt;br /&gt;&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Threashold in milliseconds before issuing a fatal log&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        private readonly long fatalCount = 0;&lt;br /&gt;&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Stopwatch to determine how long between starting and stopping&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        private Stopwatch sw = new Stopwatch();&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Simple constructor that generates a default message for the current log level&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        public LogTimer()&lt;br /&gt;        {&lt;br /&gt;            sw.Start();&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Simple constructor that generates the messages for the current log level&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        /// &amp;lt;param name="message"&amp;gt;The message to log&amp;lt;/param&amp;gt;&lt;br /&gt;        public LogTimer(string message) : base()&lt;br /&gt;        {&lt;br /&gt;            msg = message;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Most comprehensive constructor. Allows setting all the properties.&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        /// &amp;lt;param name="message"&amp;gt;Message to log&amp;lt;/param&amp;gt;&lt;br /&gt;        /// &amp;lt;param name="fatal"&amp;gt;Threshold for fatal logs&amp;lt;/param&amp;gt;&lt;br /&gt;        /// &amp;lt;param name="error"&amp;gt;Threashold for error logs&amp;lt;/param&amp;gt;&lt;br /&gt;        /// &amp;lt;param name="warn"&amp;gt;Threashold for warn logs&amp;lt;/param&amp;gt;&lt;br /&gt;        /// &amp;lt;param name="info"&amp;gt;Threashold for info logs&amp;lt;/param&amp;gt;&lt;br /&gt;        /// &amp;lt;param name="debug"&amp;gt;Threadhold for debug logs&amp;lt;/param&amp;gt;&lt;br /&gt;        public LogTimer(string message, long fatal, long error, long warn, long info, long debug) : base()&lt;br /&gt;        {&lt;br /&gt;            msg = message;&lt;br /&gt;            fatalCount = fatal;&lt;br /&gt;            errorCount = error;&lt;br /&gt;            warnCount = warn;&lt;br /&gt;            infoCount = info;&lt;br /&gt;            debugCount = debug;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Construct allowing setting the message and threasholds for fatal, error, warn, and info.&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        /// &amp;lt;param name="message"&amp;gt;Message to log&amp;lt;/param&amp;gt;&lt;br /&gt;        /// &amp;lt;param name="fatal"&amp;gt;Threshold for fatal logs&amp;lt;/param&amp;gt;&lt;br /&gt;        /// &amp;lt;param name="error"&amp;gt;Threashold for error logs&amp;lt;/param&amp;gt;&lt;br /&gt;        /// &amp;lt;param name="warn"&amp;gt;Threashold for warn logs&amp;lt;/param&amp;gt;&lt;br /&gt;        /// &amp;lt;param name="info"&amp;gt;Threashold for info and debug logs&amp;lt;/param&amp;gt;&lt;br /&gt;        public LogTimer(string message, long fatal, long error, long warn, long info) : base()&lt;br /&gt;        {&lt;br /&gt;            msg = message;&lt;br /&gt;            fatalCount = fatal;&lt;br /&gt;            errorCount = error;&lt;br /&gt;            warnCount = warn;&lt;br /&gt;            infoCount = info;&lt;br /&gt;            debugCount = info;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Construct allowing setting the message and threasholds for&lt;br /&gt;        /// fatal, error, and warn.&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        /// &amp;lt;param name="message"&amp;gt;Message to log&amp;lt;/param&amp;gt;&lt;br /&gt;        /// &amp;lt;param name="fatal"&amp;gt;Threshold for fatal logs&amp;lt;/param&amp;gt;&lt;br /&gt;        /// &amp;lt;param name="error"&amp;gt;Threashold for error logs&amp;lt;/param&amp;gt;&lt;br /&gt;        /// &amp;lt;param name="warn"&amp;gt;Threashold for warn, info and debug logs&amp;lt;/param&amp;gt;&lt;br /&gt;        public LogTimer(string message, long fatal, long error, long warn) : base()&lt;br /&gt;        {&lt;br /&gt;            msg = message;&lt;br /&gt;            fatalCount = fatal;&lt;br /&gt;            errorCount = error;&lt;br /&gt;            warnCount = warn;&lt;br /&gt;            infoCount = warn;&lt;br /&gt;            debugCount = warn;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Construct allowing setting the message and threasholds for&lt;br /&gt;        /// fatal and error&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        /// &amp;lt;param name="message"&amp;gt;Message to log&amp;lt;/param&amp;gt;&lt;br /&gt;        /// &amp;lt;param name="fatal"&amp;gt;Threshold for fatal logs&amp;lt;/param&amp;gt;&lt;br /&gt;        /// &amp;lt;param name="error"&amp;gt;Threashold for error, warn, info and debug logs&amp;lt;/param&amp;gt;&lt;br /&gt;        public LogTimer(string message, long fatal, long error) : base()&lt;br /&gt;        {&lt;br /&gt;            msg = message;&lt;br /&gt;            fatalCount = fatal;&lt;br /&gt;            errorCount = error;&lt;br /&gt;            warnCount = error;&lt;br /&gt;            infoCount = error;&lt;br /&gt;            debugCount = error;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Construct allowing setting the message and threashold&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        /// &amp;lt;param name="message"&amp;gt;Message to log&amp;lt;/param&amp;gt;&lt;br /&gt;        /// &amp;lt;param name="fatal"&amp;gt;Threshold for fatal, error, warn, info,&lt;br /&gt;        /// and debug logs&amp;lt;/param&amp;gt;&lt;br /&gt;        public LogTimer(string message, long fatal) : base()&lt;br /&gt;        {&lt;br /&gt;            msg = message;&lt;br /&gt;            fatalCount = fatal;&lt;br /&gt;            errorCount = fatal;&lt;br /&gt;            warnCount = fatal;&lt;br /&gt;            infoCount = fatal;&lt;br /&gt;            debugCount = fatal;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Actual destructor&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        ~LogTimer()&lt;br /&gt;        {&lt;br /&gt;            Dispose(false);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Dispose method&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        public void Dispose()&lt;br /&gt;        {&lt;br /&gt;            Dispose(true);&lt;br /&gt;            GC.SuppressFinalize(this);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Dispos method&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        /// &amp;lt;param name="disposing"&amp;gt;currently disposing&amp;lt;/param&amp;gt;&lt;br /&gt;        protected virtual void Dispose(bool disposing)&lt;br /&gt;        {&lt;br /&gt;            if (!this.disposed)&lt;br /&gt;            {&lt;br /&gt;                if (disposing)&lt;br /&gt;                {&lt;br /&gt;                    sw.Stop();&lt;br /&gt;                    long duration = sw.ElapsedMilliseconds;&lt;br /&gt;&lt;br /&gt;                    // log with the highest enabled log level&lt;br /&gt;                    // a log level is enable when IsLevelEnable and leveCount &amp;gt; 0&lt;br /&gt;                    if (log.IsFatalEnabled &amp;amp;&amp;amp; duration &amp;gt;= fatalCount)&lt;br /&gt;                    {&lt;br /&gt;                        log.Fatal(msg + duration.ToString());&lt;br /&gt;                    }&lt;br /&gt;                    else if (log.IsErrorEnabled &amp;amp;&amp;amp; duration &amp;gt;= errorCount)&lt;br /&gt;                    {&lt;br /&gt;                        log.Error(msg + duration.ToString());&lt;br /&gt;                    }&lt;br /&gt;                    else if (log.IsWarnEnabled &amp;amp;&amp;amp; duration &amp;gt;= warnCount)&lt;br /&gt;                    {&lt;br /&gt;                        log.Warn(msg + duration.ToString());&lt;br /&gt;                    }&lt;br /&gt;                    else if (log.IsInfoEnabled &amp;amp;&amp;amp; duration &amp;gt;= infoCount)&lt;br /&gt;                    {&lt;br /&gt;                        log.Info(msg + duration.ToString());&lt;br /&gt;                    }&lt;br /&gt;                    else if (log.IsDebugEnabled &amp;amp;&amp;amp; duration &amp;gt;= debugCount)&lt;br /&gt;                    {&lt;br /&gt;                        log.Debug(msg + duration.ToString());&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;            disposed = true;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7543977687602745925-2191292946442542723?l=jeffmcarthur.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jeffmcarthur.blogspot.com/feeds/2191292946442542723/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7543977687602745925&amp;postID=2191292946442542723' title='34 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/2191292946442542723'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/2191292946442542723'/><link rel='alternate' type='text/html' href='http://jeffmcarthur.blogspot.com/2009/11/log-timmer.html' title='Log Timmer'/><author><name>Jeffrey McArthur</name><uri>http://www.blogger.com/profile/08114179926352904007</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_Qg-uhnOHTis/STbiKa5SGxI/AAAAAAAAAAM/xPpYa0jlVDM/S220/Jeff+Head.jpg'/></author><thr:total>34</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7543977687602745925.post-8047414870329358443</id><published>2009-08-24T00:56:00.000-07:00</published><updated>2009-08-24T00:57:10.550-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PHP'/><category scheme='http://www.blogger.com/atom/ns#' term='Quentin Zervaas'/><category scheme='http://www.blogger.com/atom/ns#' term='Zend'/><category scheme='http://www.blogger.com/atom/ns#' term='IIS'/><title type='text'>The Lost Weekend: IIS 7, PHP, and Zend</title><content type='html'>&lt;p&gt;My plan for this weekend was to implement a new version of one of my web sites. I wanted to move from an old complicated build process to one based on using the Zend conventional modular layout. I estimated I could complete the task over the weekend. I was wrong.&lt;/p&gt;&lt;p&gt;Microsoft made a significant change by allowing IIS to run on the home versions of Vista. I could install IIS 7 on my new Vista 64 bit PC. I thought it would be a fun learning experience to use IIS 7 as a test bed while I implemented the changes. I was wrong.&lt;/p&gt;&lt;p&gt;Microsoft packaged up PHP and created an install using their new Web Platform Installer. This sounded like a quick way to get PHP up and running. If you want to get PHP up and running quickly on IIS 7, the Web Platform Installer will do that. However, if you want to use PEAR, the Web Platform Installer is a dead end. I have a problem with PEAR. I was unable to find any instructions on how to install PEAR manually. Everywhere I looked the documentation always said to run the "go-pear" script or batch file. Microsoft decided not to include that little file in their installation of PHP via the Web Platform Installer. When you install PHP via the Web Platform Installer on Vista 64 PHP is installed in the "\Program Files (x86)\php" directory. The installer then sets the include path to ".;c:\php5\pear" even though there is no php5 directory created. If you want PEAR and PHP on IIS, you want to avoid using the Web Platform Installer. Instead, use the "installer version" found at "windows.php.net". When you install, make sure you change the installation directory to "\php5". I also recommend you install PEAR, which is an option with the "installer version". I thought the Web Platform Installer quickly set up PHP and PEAR. I was wrong.&lt;/p&gt;&lt;p&gt;When you install IIS 7, it does not include a URL Rewrite Module. Only two things were quick and easy this weekend. The first was installing the IIS URL Rewrite Module and importing the rewrite rules from Apache. The second was downloading and installing the Zend Framework. The Zend Framework is a .Zip file you download, and decompress to anywhere you choose.&lt;/p&gt;&lt;p&gt;I used the Zend Framework before. I never started a project using MVC from scratch. I wanted to use the conventional modular layout to support three levels. There were tutorials that showed how to set this up. It looked very simple to me. I was wrong.&lt;/p&gt;&lt;p&gt;In previous entries, I mentioned "Practical Web 2.0 Applications with PHP" by Quentin Zervaas. Apress published the book in December of 2008. It is already out of date. About the time the book was published version 1.8 of the framework was released which deprecated the use of Zend_Loader's autoloader. I thought I could use the tutorial in the book by Zervaas to build a site from scratch. I was wrong.&lt;/p&gt;&lt;p&gt;I set up my site with a single controller. I kept getting the error "Invalid controller specified". I spent hours checking my directory structure. I googled the error message. Most web sites suggested that there was a problem with the file or directory casing. I am using IIS 7 on Vista. Files and directory casing should not be an issue. I thought I had some sort of typo in some file. I was wrong.&lt;/p&gt;&lt;p&gt;Finally, after much pain and cursing I found the problem. The problem is auto-rendering. The Zend framework automatically goes hunting for the template with auto-rendering enabled. Most of the sample code has a hidden assumption that auto-rendering is off. This is no longer true with the default configuration. I was getting the error "Invalid controller specified". The problem was not with the controller but with the view. Here is a situation where the MVC separation in Zend is poorly constructed. Zend generates an inappropriate error message. &lt;/p&gt;&lt;p&gt;Overall, I lost a weekend getting IIS 7, PHP, and Zend working. I did not finish redesigning my website. I still have a lot of work ahead. I was not expecting a major learning experience this weekend. I was wrong.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7543977687602745925-8047414870329358443?l=jeffmcarthur.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jeffmcarthur.blogspot.com/feeds/8047414870329358443/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7543977687602745925&amp;postID=8047414870329358443' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/8047414870329358443'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/8047414870329358443'/><link rel='alternate' type='text/html' href='http://jeffmcarthur.blogspot.com/2009/08/lost-weekend-iis-7-php-and-zend.html' title='The Lost Weekend: IIS 7, PHP, and Zend'/><author><name>Jeffrey McArthur</name><uri>http://www.blogger.com/profile/08114179926352904007</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_Qg-uhnOHTis/STbiKa5SGxI/AAAAAAAAAAM/xPpYa0jlVDM/S220/Jeff+Head.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7543977687602745925.post-8182254645705981420</id><published>2009-07-25T07:13:00.000-07:00</published><updated>2009-07-25T07:14:32.732-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Delphi'/><category scheme='http://www.blogger.com/atom/ns#' term='regular-expression'/><category scheme='http://www.blogger.com/atom/ns#' term='XHTML'/><category scheme='http://www.blogger.com/atom/ns#' term='XML'/><category scheme='http://www.blogger.com/atom/ns#' term='SGML'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='validation'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><category scheme='http://www.blogger.com/atom/ns#' term='HTML'/><title type='text'>Trust but Validate</title><content type='html'>&lt;p&gt;The phrase "trust but verify" came out of the cold war. I learned SGML while working at ATLIS Systems. For many years ATLIS was a leader in SGML. One phrase coined by ATLIS was, "If a system is not based on a DTD and checked by an SGML parser, it is NOT SGML." In essence, you had to validate each and every instance. HTML (up through version 4) is not XML. HTML (up through version 4) is an SGML application. XML replaced SGML. I am amazed at how few XML aware applications never bother to create a DTD or Schema for the XML.&lt;/p&gt;&lt;p&gt;Years ago, I created a tool to help maintain my websites. The tool initially started out in Python. I really like the way the regular-expression library integrates with Python. Python refers to everything as an object. This allows putting function pointers into dictionaries and passing them to other functions. This was an important feature in the tool I created to maintain my websites. I created the user interface in Delphi. There is a mechanism to integrate Python and Delphi. I could quickly prototype the core regular expression replacements in Python and use that code in the finished user interface application.&lt;/p&gt;&lt;p&gt;I rewrote the Delphi code in C#. Although I thought the code was relatively clean, there were a few minor points that needed refactoring. I considered integrating my Python into C#. Instead, I found that the C# regular-expression library uses delegates. C# delegates are similar to function pointers in C/C++. Delegates allow you to pass function pointers to the regular-expression library just like you can do in Python. The C# syntax is a bit more wordy (verbosity never bothers me) than Python but a lot more strict. Python gives you enough rope to hang yourself by its lack of type checking. C# is a much strong typed language. I refactored my old Delphi and Python program into C#.&lt;/p&gt;&lt;p&gt;Microsoft added a lot of support for XML and HTML to .Net. One feature I did not have in the old version of my tool was a mechanism to validate the document. The code below shows how to validate a document in C#.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;StringReader sr = new StringReader(WebPage);&lt;br /&gt;XmlReaderSettings settings = new XmlReaderSettings();&lt;br /&gt;settings.ProhibitDtd = false;&lt;br /&gt;settings.ValidationEventHandler += new ValidationEventHandler(PageValidationEvent);&lt;br /&gt;XmlReader xvr = XmlReader.Create(sr, settings);&lt;br /&gt;try&lt;br /&gt;{&lt;br /&gt;    while (xvr.Read())&lt;br /&gt;    {&lt;br /&gt;        // do nothing&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;catch (XmlException e)&lt;br /&gt;{&lt;br /&gt;    // handle any validation errors&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The code below handles a single error.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;public static void PageValidationEvent(object sender, ValidationEventArgs args)&lt;br /&gt;{&lt;br /&gt;    // code to handle each error&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Microsoft's validation is only mediocre. It catches most errors but not all. But for a few simple lines of code it is worth the effort.&lt;/p&gt;&lt;p&gt;I try to be very careful and ensure that my documents are correctly formed and valid. I started a major redesign of one of my websites. I originally built the site using my Delphi-Python tool. I had not done any major work on the site in years. When I started rebuilding the site using the C# version of my tool I found a lot of validation errors. Even though I tried to be careful I made some simple mistakes. &lt;/p&gt;&lt;p&gt;Those mistakes are the reason why I decided to write this article I titled "Trust but Validate". Now that I think about it, don't both with the trust, just validate your HTML and XML.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7543977687602745925-8182254645705981420?l=jeffmcarthur.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jeffmcarthur.blogspot.com/feeds/8182254645705981420/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7543977687602745925&amp;postID=8182254645705981420' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/8182254645705981420'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/8182254645705981420'/><link rel='alternate' type='text/html' href='http://jeffmcarthur.blogspot.com/2009/07/trust-but-validate.html' title='Trust but Validate'/><author><name>Jeffrey McArthur</name><uri>http://www.blogger.com/profile/08114179926352904007</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_Qg-uhnOHTis/STbiKa5SGxI/AAAAAAAAAAM/xPpYa0jlVDM/S220/Jeff+Head.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7543977687602745925.post-3138901840156369261</id><published>2009-07-14T20:39:00.000-07:00</published><updated>2009-07-14T20:41:38.651-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GDI'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows Mobile'/><title type='text'>Developing using C# for Windows Mobile Suddenly Got Easier</title><content type='html'>&lt;p&gt;I complained Microsoft did not make all the GDI and Win32 equivalent for C#. Well they are. Microsoft just didn't bother to make it easy to find. For me, it took a couple of days of searching before I stumbled on this great article: &lt;a href="http://msdn.microsoft.com/en-us/magazine/cc185722.aspx"&gt;Optimize Your Pocket PC Development with the .NET Compact Framework&lt;/a&gt;. The title does not sound that important. This article gives you lots and lots of code you need if you want to develop using C# on Windows Mobile. For example, it provides a mapping of a large number of Win32 equivalent calls providing all the P/Involk code, constants, and enumerations. It also provides a Gdi class that maps a lot of the GDI calls. I wish I had found this article a couple of days ago.&lt;/p&gt;&lt;p&gt;The article does not describe everything included in the source code. It contains libraries Brushes, Fonts, Font Cache, GDI, Pens, the Registry, and Win32 calls. If you are developing for Windows Mobile and using C# you need to download the source code and look at all the hidden goodies.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7543977687602745925-3138901840156369261?l=jeffmcarthur.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jeffmcarthur.blogspot.com/feeds/3138901840156369261/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7543977687602745925&amp;postID=3138901840156369261' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/3138901840156369261'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/3138901840156369261'/><link rel='alternate' type='text/html' href='http://jeffmcarthur.blogspot.com/2009/07/developing-using-c-for-windows-mobile.html' title='Developing using C# for Windows Mobile Suddenly Got Easier'/><author><name>Jeffrey McArthur</name><uri>http://www.blogger.com/profile/08114179926352904007</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_Qg-uhnOHTis/STbiKa5SGxI/AAAAAAAAAAM/xPpYa0jlVDM/S220/Jeff+Head.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7543977687602745925.post-5961163139312326549</id><published>2009-07-13T21:36:00.000-07:00</published><updated>2009-07-13T21:50:54.976-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='Twitter'/><category scheme='http://www.blogger.com/atom/ns#' term='P/Involk'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows Mobile'/><category scheme='http://www.blogger.com/atom/ns#' term='Quakk'/><title type='text'>Developing using C# for Windows Mobile is harder than it should be</title><content type='html'>&lt;p&gt;I got side tracked today and starting playing with &lt;a href="http://www.anthonyburns.co.uk/Quakk/"&gt;Quakk&lt;/a&gt;, a &lt;a href="http://twitter.com"&gt;Twitter&lt;/a&gt; client for Windows Mobile. It was a good time to peak under the hood and learn how the &lt;a href="http://apiwiki.twitter.com/"&gt;Twitter API&lt;/a&gt; worked as well as see how someone implemented a Windows Mobile client. &lt;a href="http://www.anthonyburns.co.uk/Quakk/"&gt;Quakk&lt;/a&gt; compiles and runs under Visual Studio 2008 once you get all the mobile development tools downloaded, installed, and configured. Microsoft makes that harder than it should. For example, in order to connect your mobile VM to the Internet you have to install Microsoft Virtual PC. Microsoft used to allow you download the network drivers. Now you have to install their entire Virtual PC in order to use the network drivers for the Windows Mobile VMs.&lt;/p&gt;&lt;p&gt;The Mobile VMs allow you to scale up the VM so it easier to read. Otherwise I would be stuck with 240x240 pixel emulation on a large screen. After you make the change you need to save the configuration or it will revert back. The same is true with the network settings.&lt;/p&gt;&lt;p&gt;Once I got &lt;a href="http://www.anthonyburns.co.uk/Quakk/"&gt;Quakk&lt;/a&gt; running I took a good look at the code. Parts were well comments. Parts use lots of "magic numbers". For example, there were several places where the code would subtract 13 from the width of the panel. The default width of a vertical scroll bar is 13 pixels on Windows Mobile. At a bare minimum, that should have been a constant. It was not.&lt;/p&gt;&lt;p&gt;I decided to start removing the "magic numbers". This was a lot harder than it sounds. If you develop for Windows, then the System.Windows.Forms.SystemInformation class provides a great deal of information. Unfortunately, if you develop for Windows Mobile, Microsoft decided to lobotomize this class. This means for most applications you need to use the lower level GetSystemMetrics. This is fine if you are programming in C++. But if you are using C#, well things are harder than they should be. After much searching, I found the code to P/Involk the GetSystemMetrics call. Pinvolk.net is a useful resource, but as I write this, they did not document the Windows Mobile version of the GetSystemMetrics call; which is slightly different than the GetSystemMetrics call for Windows. Again, Microsoft made things a bit harder than they should be by changes the DLL that contains GetSystemMetrics when they ported it to Windows Mobile. My code for GetSystemMetrics is below.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Runtime.InteropServices;&lt;br /&gt;&lt;br /&gt;namespace WindowsAPI&lt;br /&gt;{&lt;br /&gt;    public static class WinAPI&lt;br /&gt;    {&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Call the system metrics function&lt;br /&gt;        /// &lt;br /&gt;        /// Windows mobile uses coredll.dll and not user32.dll&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        /// &amp;lt;param name="smIndex"&amp;gt;The value to return&amp;lt;/param&amp;gt;&lt;br /&gt;        /// &amp;lt;returns&amp;gt;Integer value requested&amp;lt;/returns&amp;gt;&lt;br /&gt;        [DllImport("coredll.dll")]&lt;br /&gt;        public static extern int GetSystemMetrics(SystemMetric smIndex);&lt;br /&gt;&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Windows mobile uses coredll.dll and not user32.dll&lt;br /&gt;        /// &lt;br /&gt;        /// Flags used with the Windows API (User32.dll):GetSystemMetrics(SystemMetric smIndex)&lt;br /&gt;        ///   &lt;br /&gt;        /// This Enum and declaration signature was written by Gabriel T. Sharp&lt;br /&gt;        /// ai_productions@verizon.net or osirisgothra@hotmail.com&lt;br /&gt;        /// Obtained on pinvoke.net, please contribute your code to support the wiki!&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        public enum SystemMetric : int&lt;br /&gt;        {&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            ///  Width of the screen of the primary display monitor, in pixels. This is the same values obtained by calling GetDeviceCaps as follows: GetDeviceCaps( hdcPrimaryMonitor, HORZRES).&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CXSCREEN = 0,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Height of the screen of the primary display monitor, in pixels. This is the same values obtained by calling GetDeviceCaps as follows: GetDeviceCaps( hdcPrimaryMonitor, VERTRES).&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CYSCREEN = 1,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Width of a horizontal scroll bar, in pixels.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CYVSCROLL = 2,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Height of a horizontal scroll bar, in pixels.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CXVSCROLL = 3,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Height of a caption area, in pixels.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CYCAPTION = 4,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Width of a window border, in pixels. This is equivalent to the SM_CXEDGE value for windows with the 3-D look. &lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CXBORDER = 5,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Height of a window border, in pixels. This is equivalent to the SM_CYEDGE value for windows with the 3-D look. &lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CYBORDER = 6,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Thickness of the frame around the perimeter of a window that has a caption but is not sizable, in pixels. SM_CXFIXEDFRAME is the height of the horizontal border and SM_CYFIXEDFRAME is the width of the vertical border. &lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CXDLGFRAME = 7,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Thickness of the frame around the perimeter of a window that has a caption but is not sizable, in pixels. SM_CXFIXEDFRAME is the height of the horizontal border and SM_CYFIXEDFRAME is the width of the vertical border. &lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CYDLGFRAME = 8,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Height of the thumb box in a vertical scroll bar, in pixels&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CYVTHUMB = 9,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Width of the thumb box in a horizontal scroll bar, in pixels.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CXHTHUMB = 10,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Default width of an icon, in pixels. The LoadIcon function can load only icons with the dimensions specified by SM_CXICON and SM_CYICON&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CXICON = 11,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Default height of an icon, in pixels. The LoadIcon function can load only icons with the dimensions SM_CXICON and SM_CYICON.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CYICON = 12,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Width of a cursor, in pixels. The system cannot create cursors of other sizes.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CXCURSOR = 13,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Height of a cursor, in pixels. The system cannot create cursors of other sizes.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CYCURSOR = 14,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Height of a single-line menu bar, in pixels.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CYMENU = 15,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Width of the client area for a full-screen window on the primary display monitor, in pixels. To get the coordinates of the portion of the screen not obscured by the system taskbar or by application desktop toolbars, call the SystemParametersInfo function with the SPI_GETWORKAREA value.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CXFULLSCREEN = 16,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Height of the client area for a full-screen window on the primary display monitor, in pixels. To get the coordinates of the portion of the screen not obscured by the system taskbar or by application desktop toolbars, call the SystemParametersInfo function with the SPI_GETWORKAREA value.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CYFULLSCREEN = 17,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// For double byte character set versions of the system, this is the height of the Kanji window at the bottom of the screen, in pixels&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CYKANJIWINDOW = 18,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Nonzero if a mouse with a wheel is installed; zero otherwise&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_MOUSEWHEELPRESENT = 75,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Height of the arrow bitmap on a vertical scroll bar, in pixels.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CYHSCROLL = 20,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Width of the arrow bitmap on a horizontal scroll bar, in pixels.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CXHSCROLL = 21,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Nonzero if the debug version of User.exe is installed; zero otherwise.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_DEBUG = 22,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Nonzero if the left and right mouse buttons are reversed; zero otherwise.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_SWAPBUTTON = 23,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Reserved for future use&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_RESERVED1 = 24,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Reserved for future use&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_RESERVED2 = 25,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Reserved for future use&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_RESERVED3 = 26,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Reserved for future use&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_RESERVED4 = 27,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Minimum width of a window, in pixels.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CXMIN = 28,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Minimum height of a window, in pixels.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CYMIN = 29,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Width of a button in a window's caption or title bar, in pixels.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CXSIZE = 30,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Height of a button in a window's caption or title bar, in pixels.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CYSIZE = 31,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Thickness of the sizing border around the perimeter of a window that can be resized, in pixels. SM_CXSIZEFRAME is the width of the horizontal border, and SM_CYSIZEFRAME is the height of the vertical border. &lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CXFRAME = 32,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Thickness of the sizing border around the perimeter of a window that can be resized, in pixels. SM_CXSIZEFRAME is the width of the horizontal border, and SM_CYSIZEFRAME is the height of the vertical border. &lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CYFRAME = 33,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Minimum tracking width of a window, in pixels. The user cannot drag the window frame to a size smaller than these dimensions. A window can override this value by processing the WM_GETMINMAXINFO message.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CXMINTRACK = 34,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Minimum tracking height of a window, in pixels. The user cannot drag the window frame to a size smaller than these dimensions. A window can override this value by processing the WM_GETMINMAXINFO message&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CYMINTRACK = 35,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Width of the rectangle around the location of a first click in a double-click sequence, in pixels. The second click must occur within the rectangle defined by SM_CXDOUBLECLK and SM_CYDOUBLECLK for the system to consider the two clicks a double-click&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CXDOUBLECLK = 36,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Height of the rectangle around the location of a first click in a double-click sequence, in pixels. The second click must occur within the rectangle defined by SM_CXDOUBLECLK and SM_CYDOUBLECLK for the system to consider the two clicks a double-click. (The two clicks must also occur within a specified time.) &lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CYDOUBLECLK = 37,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Width of a grid cell for items in large icon view, in pixels. Each item fits into a rectangle of size SM_CXICONSPACING by SM_CYICONSPACING when arranged. This value is always greater than or equal to SM_CXICON&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CXICONSPACING = 38,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Height of a grid cell for items in large icon view, in pixels. Each item fits into a rectangle of size SM_CXICONSPACING by SM_CYICONSPACING when arranged. This value is always greater than or equal to SM_CYICON.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CYICONSPACING = 39,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Nonzero if drop-down menus are right-aligned with the corresponding menu-bar item; zero if the menus are left-aligned.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_MENUDROPALIGNMENT = 40,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Nonzero if the Microsoft Windows for Pen computing extensions are installed; zero otherwise.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_PENWINDOWS = 41,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Nonzero if User32.dll supports DBCS; zero otherwise. (WinMe/95/98): Unicode&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_DBCSENABLED = 42,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Number of buttons on mouse, or zero if no mouse is installed.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CMOUSEBUTTONS = 43,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Identical Values Changed After Windows NT 4.0  &lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CXFIXEDFRAME = SM_CXDLGFRAME,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Identical Values Changed After Windows NT 4.0&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CYFIXEDFRAME = SM_CYDLGFRAME,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Identical Values Changed After Windows NT 4.0&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CXSIZEFRAME = SM_CXFRAME,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Identical Values Changed After Windows NT 4.0&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CYSIZEFRAME = SM_CYFRAME,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Nonzero if security is present; zero otherwise.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_SECURE = 44,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Width of a 3-D border, in pixels. This is the 3-D counterpart of SM_CXBORDER&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CXEDGE = 45,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Height of a 3-D border, in pixels. This is the 3-D counterpart of SM_CYBORDER&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CYEDGE = 46,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Width of a grid cell for a minimized window, in pixels. Each minimized window fits into a rectangle this size when arranged. This value is always greater than or equal to SM_CXMINIMIZED.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CXMINSPACING = 47,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Height of a grid cell for a minimized window, in pixels. Each minimized window fits into a rectangle this size when arranged. This value is always greater than or equal to SM_CYMINIMIZED.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CYMINSPACING = 48,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Recommended width of a small icon, in pixels. Small icons typically appear in window captions and in small icon view&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CXSMICON = 49,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Recommended height of a small icon, in pixels. Small icons typically appear in window captions and in small icon view.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CYSMICON = 50,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Height of a small caption, in pixels&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CYSMCAPTION = 51,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Width of small caption buttons, in pixels.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CXSMSIZE = 52,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Height of small caption buttons, in pixels.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CYSMSIZE = 53,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Width of menu bar buttons, such as the child window close button used in the multiple document interface, in pixels.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CXMENUSIZE = 54,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Height of menu bar buttons, such as the child window close button used in the multiple document interface, in pixels.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CYMENUSIZE = 55,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Flags specifying how the system arranged minimized windows&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_ARRANGE = 56,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Width of a minimized window, in pixels.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CXMINIMIZED = 57,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Height of a minimized window, in pixels.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CYMINIMIZED = 58,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Default maximum width of a window that has a caption and sizing borders, in pixels. This metric refers to the entire desktop. The user cannot drag the window frame to a size larger than these dimensions. A window can override this value by processing the WM_GETMINMAXINFO message.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CXMAXTRACK = 59,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Default maximum height of a window that has a caption and sizing borders, in pixels. This metric refers to the entire desktop. The user cannot drag the window frame to a size larger than these dimensions. A window can override this value by processing the WM_GETMINMAXINFO message.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CYMAXTRACK = 60,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Default width, in pixels, of a maximized top-level window on the primary display monitor.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CXMAXIMIZED = 61,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Default height, in pixels, of a maximized top-level window on the primary display monitor.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CYMAXIMIZED = 62,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Least significant bit is set if a network is present; otherwise, it is cleared. The other bits are reserved for future use&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_NETWORK = 63,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Value that specifies how the system was started: 0-normal, 1-failsafe, 2-failsafe /w net&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CLEANBOOT = 67,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Width of a rectangle centered on a drag point to allow for limited movement of the mouse pointer before a drag operation begins, in pixels. &lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CXDRAG = 68,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Height of a rectangle centered on a drag point to allow for limited movement of the mouse pointer before a drag operation begins. This value is in pixels. It allows the user to click and release the mouse button easily without unintentionally starting a drag operation.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CYDRAG = 69,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Nonzero if the user requires an application to present information visually in situations where it would otherwise present the information only in audible form; zero otherwise. &lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_SHOWSOUNDS = 70,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Width of the default menu check-mark bitmap, in pixels.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CXMENUCHECK = 71,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Height of the default menu check-mark bitmap, in pixels.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CYMENUCHECK = 72,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Nonzero if the computer has a low-end (slow) processor; zero otherwise&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_SLOWMACHINE = 73,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Nonzero if the system is enabled for Hebrew and Arabic languages, zero if not.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_MIDEASTENABLED = 74,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Nonzero if a mouse is installed; zero otherwise. This value is rarely zero, because of support for virtual mice and because some systems detect the presence of the port instead of the presence of a mouse.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_MOUSEPRESENT = 19,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Windows 2000 (v5.0+) Coordinate of the top of the virtual screen&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_XVIRTUALSCREEN = 76,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Windows 2000 (v5.0+) Coordinate of the left of the virtual screen&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_YVIRTUALSCREEN = 77,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Windows 2000 (v5.0+) Width of the virtual screen&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CXVIRTUALSCREEN = 78,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Windows 2000 (v5.0+) Height of the virtual screen&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CYVIRTUALSCREEN = 79,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Number of display monitors on the desktop&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CMONITORS = 80,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Windows XP (v5.1+) Nonzero if all the display monitors have the same color format, zero otherwise. Note that two displays can have the same bit depth, but different color formats. For example, the red, green, and blue pixels can be encoded with different numbers of bits, or those bits can be located in different places in a pixel's color value. &lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_SAMEDISPLAYFORMAT = 81,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Windows XP (v5.1+) Nonzero if Input Method Manager/Input Method Editor features are enabled; zero otherwise&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_IMMENABLED = 82,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Windows XP (v5.1+) Width of the left and right edges of the focus rectangle drawn by DrawFocusRect. This value is in pixels. &lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CXFOCUSBORDER = 83,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Windows XP (v5.1+) Height of the top and bottom edges of the focus rectangle drawn by DrawFocusRect. This value is in pixels. &lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CYFOCUSBORDER = 84,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Nonzero if the current operating system is the Windows XP Tablet PC edition, zero if not.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_TABLETPC = 86,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Nonzero if the current operating system is the Windows XP, Media Center Edition, zero if not.&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_MEDIACENTER = 87,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Metrics Other&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CMETRICS_OTHER = 76,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Metrics Windows 2000&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CMETRICS_2000 = 83,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Metrics Windows NT&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_CMETRICS_NT = 88,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Windows XP (v5.1+) This system metric is used in a Terminal Services environment. If the calling process is associated with a Terminal Services client session, the return value is nonzero. If the calling process is associated with the Terminal Server console session, the return value is zero. The console session is not necessarily the physical console - see WTSGetActiveConsoleSessionId for more information. &lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_REMOTESESSION = 0x1000,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Windows XP (v5.1+) Nonzero if the current session is shutting down; zero otherwise&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_SHUTTINGDOWN = 0x2000,&lt;br /&gt;            /// &amp;lt;summary&amp;gt;&lt;br /&gt;            /// Windows XP (v5.1+) This system metric is used in a Terminal Services environment. Its value is nonzero if the current session is remotely controlled; zero otherwise&lt;br /&gt;            /// &amp;lt;/summary&amp;gt;&lt;br /&gt;            SM_REMOTECONTROL = 0x2001,&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now I was able to remove one set of magic numbers from &lt;a href="http://www.anthonyburns.co.uk/Quakk/"&gt;Quakk&lt;/a&gt;. I run &lt;a href="http://www.anthonyburns.co.uk/Quakk/"&gt;Quakk&lt;/a&gt; on an old Treo 700w. The Treo has a 240x240 screen. If you tweet using &lt;a href="http://www.anthonyburns.co.uk/Quakk/"&gt;Quakk&lt;/a&gt; on a 240x240 device the system displays a horizontal scroll box. &lt;a href="http://www.anthonyburns.co.uk/Quakk/"&gt;Quakk&lt;/a&gt; made some incorrect assumptions about screen size. I was able to fix the horizontal scroll bar problem with some minor code changes. In that same code, &lt;a href="http://www.anthonyburns.co.uk/Quakk/"&gt;Quakk&lt;/a&gt; makes some assumptions about the font size and placement of the input boxes. The correct way to fix that is to call the SHGetUIMetrics to get the current system font size. SHGetUIMetrics is not available without using a P/Involk. I found one &lt;a href="http://blogs.msdn.com/windowsmobile/archive/2004/04/03/107203.aspx"&gt;article&lt;/a&gt; with the sample code.&lt;/p&gt;&lt;p&gt;I thought I would make a few changes. I did, but it was a lot harder than it should have been.&lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7543977687602745925-5961163139312326549?l=jeffmcarthur.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jeffmcarthur.blogspot.com/feeds/5961163139312326549/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7543977687602745925&amp;postID=5961163139312326549' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/5961163139312326549'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/5961163139312326549'/><link rel='alternate' type='text/html' href='http://jeffmcarthur.blogspot.com/2009/07/i-got-side-tracked-today-and-starting.html' title='Developing using C# for Windows Mobile is harder than it should be'/><author><name>Jeffrey McArthur</name><uri>http://www.blogger.com/profile/08114179926352904007</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_Qg-uhnOHTis/STbiKa5SGxI/AAAAAAAAAAM/xPpYa0jlVDM/S220/Jeff+Head.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7543977687602745925.post-5929002148597517070</id><published>2009-06-07T21:01:00.000-07:00</published><updated>2009-06-07T21:02:41.978-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='multi-threaded'/><category scheme='http://www.blogger.com/atom/ns#' term='Alienware'/><category scheme='http://www.blogger.com/atom/ns#' term='CPU'/><category scheme='http://www.blogger.com/atom/ns#' term='C++'/><category scheme='http://www.blogger.com/atom/ns#' term='GPU'/><title type='text'>Technical Challenge of Multiple CPUs</title><content type='html'>&lt;p&gt;One of the biggest technical challenges in developing software is taking advantage of multiple CPUs. Processor speed has basically stalled. Intel and AMD are putting more and more CPUs into the same chip. Right now dual and quad core chips are becoming common. If you are talking two years away, then by Moore's Law, you will be seeing eight or more cores in most systems. If it is three years away, you could be seeing sixteen or more cores.&lt;/p&gt;&lt;p&gt;Currently, only very high end systems have multiple GPUs. We had one system at a company I used to work for that had four GPUs (all very high end stuff doing medical imaging). But just like CPUs, multiple GPUs are going to be more and more common.&lt;/p&gt;&lt;p&gt;The challenge of writing code that supports multiple processors working in parallel is the real challenge. Some argue that current computer languages do not support that well. In my experience, threads (which are supposed to be light weight processes) do not scale well on multi-core CPU systems. We had a Java application with six main threads running on a system with two dual core chips (total of 4 cores) and we saw almost no performance gain for that application over running on a single core CPU. The system performed better because the system basically gave one CPU to the SQL server and another to the OS, but our multi-threaded application did not get any faster. You could blame that on Java, but putting the blame there does not solve the problem. Also we had similar problems with a multi-threaded application written in C++. The current state of compiler and operating system support for multiple CPUs is limited.&lt;/p&gt;&lt;p&gt;Right now I am drooling over the new Alienware M17x. You can get a laptop with a quad core CPU and dual GPUs. That would be a good replacement for aging Alienware laptop. It has been a great system, but it is getting old.&lt;/p&gt;&lt;p&gt;I hope that the operating system and programs will take full advantage of the 16 CPUs and 8 GPUs I hope to have in the computer I hope to have in a couple of years.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7543977687602745925-5929002148597517070?l=jeffmcarthur.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jeffmcarthur.blogspot.com/feeds/5929002148597517070/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7543977687602745925&amp;postID=5929002148597517070' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/5929002148597517070'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/5929002148597517070'/><link rel='alternate' type='text/html' href='http://jeffmcarthur.blogspot.com/2009/06/technical-challenge-of-multiple-cpus.html' title='Technical Challenge of Multiple CPUs'/><author><name>Jeffrey McArthur</name><uri>http://www.blogger.com/profile/08114179926352904007</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_Qg-uhnOHTis/STbiKa5SGxI/AAAAAAAAAAM/xPpYa0jlVDM/S220/Jeff+Head.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7543977687602745925.post-988284158500823380</id><published>2009-06-07T20:04:00.000-07:00</published><updated>2009-06-07T21:03:55.996-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Developer Tool Kit'/><category scheme='http://www.blogger.com/atom/ns#' term='6.5'/><category scheme='http://www.blogger.com/atom/ns#' term='Widgets'/><category scheme='http://www.blogger.com/atom/ns#' term='Microsoft'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows Mobile'/><title type='text'>First Impression of Windows Mobile 6.5 Developer Tool Kit</title><content type='html'>&lt;p&gt;I downloaded and installed the Windows Mobile 6.5 Developer Tool Kit. My first impression is yawn. I am putting a lot of emphasis on Windows Mobile but I found the 6.5 developer tool kit to be a big disappointment. The tool kit includes two new features: gesture API and widgets.&lt;/p&gt;&lt;p&gt;Personally, I think the gesture API is a yawn. I don't mind using a stylus. I have a nice set of pens that can print in black, red, pencil, or act as a stylus. People don't complain about using a pen on a piece of paper; why do they complain about using a stylus on a device? With a multi-function tool that can act as a pencil, pen, or stylus, I don't have to put the tool down to use a phone or PDA. I will have to play with the gesture API, but at this point it is just a yawn.&lt;/p&gt;&lt;p&gt;My first thought about widgets was so what? My second thought was about the same. The only reason widgets are at all interesting is they point out the capabilities of the new browser included on Windows Mobile 6.5. It is too early for me to tell, but that may be a reason alone to upgrade to 6.5. The only thing that worries me is the example widget posted by Microsoft does not use cascading style sheets or JavaScript. The "hello world" example makes me worry that the support for CSS and JavaScript may still be a little lacking. I will wait until someone else spends the time and effort documenting what works and what does not before do anything serious with widgets. One interesting thing about widgets is Microsoft actually points to the &lt;a href="http://www.w3.org/TR/2007/WD-widgets-reqs-20070209/"&gt;W3C standard for Widgets&lt;/a&gt;. A Google search about Widgets pulls out this gem: &lt;a href="http://www.macnn.com/articles/09/04/07/apple.threatens.w3c/"&gt;Apple threatens to block W3C widget standard&lt;/a&gt;. I am not worried that Apple's attempt to block the W3C will have any impact on Microsoft. After all, Microsoft will do what it has always done, create a non-standard way. But this time Microsoft could say, "Don't blame us, Apple forced us to."&lt;/p&gt;&lt;p&gt;The 6.5 tool kit screams, "I was pushed out quickly!" A lot of documentation about 6.5 on the MSDN site is missing. I found several broken links just trying to find out what was new. Another thing that reinforces that is the DRK or &lt;a href="http://blogs.msdn.com/windowsmobile/archive/2009/06/04/sdk-dtk-drk-wtf.aspx"&gt;Developer Resource Kit&lt;/a&gt; will not be available until July. Microsoft is going to charge $9.99 for the DRK. I was going to order a copy. However the MSDN order site asked for my credit card without using a secure web page. The page does not display the little lock icon in IE8. This is probably another bug caused by pushing out the release. Until Microsoft fixes this, I will not put my credit card information into an unsecure web page. I discourage anyone from ordering the DRK until you can order it from a secure web page.&lt;/p&gt;&lt;p&gt;Unless you are hot for the gesture API or want to explore the capabilities of the new browser there is little need to download the Windows Mobile 6.5 Developer Tool Kit.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7543977687602745925-988284158500823380?l=jeffmcarthur.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jeffmcarthur.blogspot.com/feeds/988284158500823380/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7543977687602745925&amp;postID=988284158500823380' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/988284158500823380'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/988284158500823380'/><link rel='alternate' type='text/html' href='http://jeffmcarthur.blogspot.com/2009/06/first-impression-of-windows-mobile-65.html' title='First Impression of Windows Mobile 6.5 Developer Tool Kit'/><author><name>Jeffrey McArthur</name><uri>http://www.blogger.com/profile/08114179926352904007</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_Qg-uhnOHTis/STbiKa5SGxI/AAAAAAAAAAM/xPpYa0jlVDM/S220/Jeff+Head.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7543977687602745925.post-7138156403736045594</id><published>2009-06-05T05:01:00.000-07:00</published><updated>2009-06-05T05:03:09.992-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CC3'/><category scheme='http://www.blogger.com/atom/ns#' term='XAML'/><category scheme='http://www.blogger.com/atom/ns#' term='Silverlight'/><category scheme='http://www.blogger.com/atom/ns#' term='Corel Draw'/><category scheme='http://www.blogger.com/atom/ns#' term='Illustrator'/><title type='text'>Converting Campaign Cartographer Files to XAML Revisited</title><content type='html'>&lt;p&gt;I have spent a lot of time working with Campaign Cartographer 3, Adobe Illustrator CS, Corel Draw 12, and Expression Blend 3. I finally came up with a solution on how to create a XAML file from Campaign Cartographer 3. CC3 will export a Windows Metafile (.emf). Adobe Illustrator CS sometimes has problems with these files. The solution is to open the .emf file in Corel Draw and save the result as an Adobe Illustrator file. This also offers the opportunity to convert all the text to curves. Adobe is very proprietary about fonts. Converting text to curves fools Adobe Illustrator and you have no more issues with fonts, at the cost of a bigger file.&lt;/p&gt;&lt;p&gt;After saving the file as an Adobe Illustrator file from Corel Draw you need to load the file into Adobe Illustrator and save it out again. Expression Blend 3 will not load the files created by Corel Draw. Adobe Illustrator adds "[converted]" to the file name when it saves the file.&lt;/p&gt;&lt;p&gt;Now you can load the converted Adobe Illustrator file directly into Expression Blend. You may need to do a few transformations to move and scale the map but it works.&lt;/p&gt;&lt;p&gt;If you export something small from CC3, then you must scale it up in Corel Draw. Full maps work without the need to scale it up.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7543977687602745925-7138156403736045594?l=jeffmcarthur.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jeffmcarthur.blogspot.com/feeds/7138156403736045594/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7543977687602745925&amp;postID=7138156403736045594' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/7138156403736045594'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/7138156403736045594'/><link rel='alternate' type='text/html' href='http://jeffmcarthur.blogspot.com/2009/06/converting-campaign-cartographer-files.html' title='Converting Campaign Cartographer Files to XAML Revisited'/><author><name>Jeffrey McArthur</name><uri>http://www.blogger.com/profile/08114179926352904007</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_Qg-uhnOHTis/STbiKa5SGxI/AAAAAAAAAAM/xPpYa0jlVDM/S220/Jeff+Head.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7543977687602745925.post-7562323659031726743</id><published>2009-06-04T18:07:00.000-07:00</published><updated>2009-06-05T05:04:08.377-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iPhone'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows Mobile'/><title type='text'>Why Windows Mobile?</title><content type='html'>&lt;p&gt;One of the questions I always get when I present the business concept for JSM Software is "why did you choose Windows Mobile?" Some are even less subtle and ask, "Why not develop for the iPhone instead?" They usually follow up with the story about how a friend of a friend made a lot of money selling some application on the iPhone.&lt;/p&gt;&lt;p&gt;Anecdotal evidence is not a good reason to start a company. I know a friend of a friend that won the lottery. It makes as much sense spending all my time, effort, and money trying to win the lottery as it does trying to make a lot of money creating applications for the iPhone. Both have the same anecdotal evidence.&lt;/p&gt;&lt;p&gt;I am trying to build a company, not win the lottery. I worked for a company that tried to "win the lottery". They came up with wonderful ideas that would change the entire company. None of it ever came to fruition. I want to emulate the conservative playbook of Woody Hayes, "three yards and a cloud of dust". Another description was "crunching, frontal assault of muscle against muscle, bone upon bone, will against will." Paraphrasing Woody Hayes, "a company will not succeed unless they regarded the challenge positively and would agree to pay the price that success demands of a team."&lt;/p&gt;&lt;p&gt;My business philosophy is simple: I want to grow a dedicated customer base by continually creating quality products. Sure I would like to make a lot of money. Everyone does. I will only focus on a market I know will provide adequate compensation for my effort.&lt;/p&gt;&lt;p&gt;One reviewer wrote me, "The iPhone market is so oversaturated with bad games, it's unbelievable." The vast number of cheep bad games put tremendous downward pricing pressure. Rick Storm wrote in his blog &lt;a href="http://stromdotcom.blogspot.com/2009/05/incredible-app-store-hype.html"&gt;The Incredible App Store Hype,&lt;/a&gt; "The hype surrounding the iPhone App Store continues to persist." Rick Storm has an application is listed as #34 on the social networking chart. According to his blog that makes him a little over $20 per day. That is a little over $7000 per year if sales continue at that rate. That is not a lot of money to me.&lt;/p&gt;&lt;p&gt;Owen Goss documented his success with his game Dapple on his blog. Owen Gloss wrote about developing applications for the iPhone, "...I suspect we'll see fewer and fewer stories about people getting suddenly very rich." (&lt;a href="http://www.streamingcolour.com/blog/2009/03/09/the-numbers-post-aka-brutal-honesty/"&gt;The Numbers Post (aka Brutal Honesty)&lt;/a&gt;). Owen Gloss spent $32,000 developing Dapple and made a total of $535 in revenue. Playing the lottery sounds like it has a lot better odds than that. I fully agree with Owen Gloss, "My hope is that we'll start seeing more developers putting out quality titles in the hopes of gradually growing a sustainable business." Owen Gloss strongly implies developing games for the iPhone is not currently a sustainable business.&lt;/p&gt;&lt;p&gt;This reminds me of a stanza from one of my favorite poems, "The Gods of the Copybook Headings" by Rudyard Kipling:&lt;/p&gt;&lt;p&gt;&lt;i&gt;With the Hopes that our World is built on they were utterly out of touch.&lt;br /&gt; They denied that the Moon was Stilton; they denied she was even Dutch.&lt;br /&gt; They denied that Wishes were Horses; they denied that a Pig had Wings.&lt;br /&gt; So we worshiped the Gods of the Market Who promised these beautiful things.&lt;/i&gt;&lt;/p&gt;&lt;p&gt;I hear a lot of people worshiping the Gods of the Market in the form of praising the iPhone App Store.&lt;/p&gt;&lt;p&gt;Before deciding on Windows Mobile I did a lot of research. This is something it appears many jumping into the fray of developing software for mobile devices do not do. Denise Marcus, a friend of mine, always said, "Do the numbers." I have always been amazed at how many people fail to do the numbers.&lt;/p&gt;&lt;p&gt;What are the numbers? According to wmpoweruser.com (&lt;a href="http://wmpoweruser.com/?p=3164"&gt;Windows Mobile hits 50 million lifetime sales &lt;/a&gt;) Microsoft has sold over 50 million Windows Mobile devices. Of that, approximately 30 million are currently in use. These numbers make sense. According to Gartner, Microsoft has been selling over 4 million windows mobile devices every quarter since 2007 (&lt;a href="http://www.gartner.com/it/page.jsp?id=827912"&gt;Gartner Says Worldwide Smartphone Sales Reached Its Lowest Growth Rate&lt;/a&gt;). Most mobile contracts are two years long. 4 million per quarter times 4 quarters per year times 2 years equals 32 million. The 30 million number may be a bit low, but it is a reasonable starting point.&lt;/p&gt;&lt;p&gt;According to Entertainment Software Association 36% report they play games on a wireless device such as a cell phone or PDA (&lt;a href="http://www.theesa.com/facts/pdfs/ESA_EF_2008.pdf"&gt;Essential Facts About the Computer and Video Game Industry&lt;/a&gt;). That means that 10.8 million Windows Mobile Users play games. The Entertainment Software Association also said that 7.6% of people who play games play role playing games. Conservatively the market for the type of games created by JSM Software is eight hundred and twenty-one thousand (821,000). If JSM Software reaches a one half of one percent market penetration, 0.5%, the sales projection is four thousand one hundred units (4,100).&lt;/p&gt;&lt;p&gt;My budget for creating a game is about $20,000. That means I need to make about $5 per unit sold. That does not include all the overhead costs in addition to the $20,000 budget. The interesting point is the average price of a role playing game for Windows Mobile on Handango is about $20. After crunching the numbers and using the wonderful spreadsheet provided by SCORE I determined I could make a living if I sold the game for $15 and sold a total of about 4,100 units over the lifespan of the game which I estimated to be one year. I bounced these numbers off of the CEOs of two other game companies. One CEO said my figures were "spot on".&lt;/p&gt;&lt;p&gt;Owen Goss said he needed to sell 9,150 units of Dapple before he would break even. I leave it to the reader to figure out what percentage of the market Dapple would require to break even. I am pretty sure it would be much larger than 0.5%.&lt;/p&gt;&lt;p&gt;The thing that puzzles me the most is why some people are so adamant I should develop for the iPhone? It seems they are trying to evangelize me to the iPhone religion. They believe all the hype and anecdotal stories. My choice to develop for Windows Mobile is an informed decision based on research. I am not embarking on creating a company based on anecdotal stories.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7543977687602745925-7562323659031726743?l=jeffmcarthur.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jeffmcarthur.blogspot.com/feeds/7562323659031726743/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7543977687602745925&amp;postID=7562323659031726743' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/7562323659031726743'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/7562323659031726743'/><link rel='alternate' type='text/html' href='http://jeffmcarthur.blogspot.com/2009/06/why-windows-mobile.html' title='Why Windows Mobile?'/><author><name>Jeffrey McArthur</name><uri>http://www.blogger.com/profile/08114179926352904007</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_Qg-uhnOHTis/STbiKa5SGxI/AAAAAAAAAAM/xPpYa0jlVDM/S220/Jeff+Head.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7543977687602745925.post-2968732744808918700</id><published>2009-05-24T16:07:00.000-07:00</published><updated>2009-05-24T16:12:53.554-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PHP'/><category scheme='http://www.blogger.com/atom/ns#' term='Quentin Zervaas'/><category scheme='http://www.blogger.com/atom/ns#' term='Zend'/><title type='text'>Problems with Practical Web 2.0 Applications with PHP</title><content type='html'>&lt;p&gt;I wanted to use the code from Quentin Zervaas's book for a website. There is a lot of good material in the book. Unfortunately, the development environment used by Quentin Zervaas must be very different from my development environment.&lt;/p&gt;

&lt;p&gt;I could not get the code to work for days. I kept fumbling around and fumbling around trying to figure out what was wrong. The first problem was the index page code was crashing and leaving no log. It took me a while, but the problem was with the EmailLogger code bye Zervaas.&lt;/p&gt;

&lt;p&gt;I am running on a Fedora 10 Linux development server. This is a minimally configured virtual machine running on my under powered VM server. This is not a production server. The first problem comes from the minimal configuration. Zervaas wrote the following code in the file "index.php":&lt;/p&gt;

&lt;pre&gt;$writer = new EmailLogger($_SERVER['SERVER_ADMIN']);

&lt;/pre&gt;

&lt;p&gt;The code is simple enough it passes the "SERVER_ADMIN" name to the EmailLogger function. On a minimally configured system the value of "SERVER_ADMIN" is "root@localhost".&lt;/p&gt;

&lt;p&gt;The EmailLogger function calls Zend_Validate_EmailAddress to make sure the email address is valid. The code is shown below:&lt;/p&gt;

&lt;pre&gt;$validator = new Zend_Validate_EmailAddress();

&lt;/pre&gt;

&lt;p&gt;The default constructor for the Zend_Validate_EmailAddress only allows DNS hostnames. This means that "root@localhost" is not a valid email address using the default parameters when creating Zend_Validate_EmailAddress. This took a long time to figure out.&lt;/p&gt;

&lt;p&gt;The solution is to tell the constructor to allow both DNS and local names. The code to do that is below:&lt;/p&gt;

&lt;pre&gt;$validator = new Zend_Validate_EmailAddress(Zend_Validate_Hostname::ALLOW_DNS | Zend_Validate_Hostname::ALLOW_LOCAL);

&lt;/pre&gt;

&lt;p&gt;The support site for "Practical Web 2.0 Applications with PHP" does not document the problem with the email validation. The support site did document the next problem I ran into. This was extra slashes at the beginning of each URL. Instead of the URL being "/index" it was "//index". I tracked down the problem quickly. But every solution that made sense to me failed. The support site has two lists of errata for the book. One list is the old and unmaintained list. The other list is the new and maintained list. The new list does not contain the errata listed on the old list.&lt;/p&gt;

&lt;p&gt;A more subtle problem is the wording of the errata. The old and unmaintained list of errata states, "When using Zend Framework 1.0.3 URLs will be generated beginning with 2 slashes." What the errata should have said is "When using Zend Framework 1.0.3 &lt;b&gt;or newer&lt;/b&gt; URLs will be generated beginning with 2 slashes." I installed the Zend Framework 1.7.8.&lt;/p&gt;

&lt;p&gt;I now have a problem with Captcha and image generation. This has been yet another learning experience.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7543977687602745925-2968732744808918700?l=jeffmcarthur.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jeffmcarthur.blogspot.com/feeds/2968732744808918700/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7543977687602745925&amp;postID=2968732744808918700' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/2968732744808918700'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/2968732744808918700'/><link rel='alternate' type='text/html' href='http://jeffmcarthur.blogspot.com/2009/05/problems-with-practical-web-20.html' title='Problems with Practical Web 2.0 Applications with PHP'/><author><name>Jeffrey McArthur</name><uri>http://www.blogger.com/profile/08114179926352904007</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_Qg-uhnOHTis/STbiKa5SGxI/AAAAAAAAAAM/xPpYa0jlVDM/S220/Jeff+Head.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7543977687602745925.post-3516847635725518245</id><published>2009-05-04T16:06:00.000-07:00</published><updated>2009-05-04T16:16:14.490-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XAML'/><category scheme='http://www.blogger.com/atom/ns#' term='mathematics'/><category scheme='http://www.blogger.com/atom/ns#' term='Silverlight'/><category scheme='http://www.blogger.com/atom/ns#' term='physics'/><category scheme='http://www.blogger.com/atom/ns#' term='rounding errors'/><title type='text'>Rounding Error Are an Important Consideration</title><content type='html'>&lt;p&gt;My background includes a lot of mathematical analysis. I took a lot of numerical analysis at the University of Utah. Many more classes than were actually required because I enjoyed the combination of math and programming. In addition, I was a teaching assistant for the computational physics classes taught as part of the master's of instrumentation program of the physics department. My first job when I left the University of Utah was working on mathematical educational software. My assignment was part of a group creating a system that symbolically solved mathematical problems. I learned a lot. One of the challenges was checking the work of the system. I spent months doing nothing but math. After giving the system a problem it would generate an answer. Often the answer didn't match the solution printed in the book. We had to determine if the computer's answer was actually the correct answer. The system may not have simplified the answer, or not done some trigonometric substitution or maybe the answer in the book was wrong. It was a lot of work. That taught me the importance of mathematical simplification.&lt;/p&gt;

&lt;p&gt;Years ago I worked on a respiratory therapy patient demographic and therapy management system. The company's core intellectual property was the set of equations modeling the treatment efficacy. The equations took the raw numbers provided by the medical instruments and the patient demography and created a meaningful human understandable diagnosis. My task was implementing those equations on a new system. I took one look at the equations and knew something was wrong with them. My background in numerical analysis told me curve fitting software created the equations. The curve fitting software mathematically matched the curve but did not simplify the equations. I convinced the professor that created the equations I could simplify them. For the next month I proved symbolically and numerically my simplification of the equations was correct. Imagine working on a month long math test. I proved the error analysis of my equations was significantly smaller than the original equations. More importantly, the resulting program ran more than ten times as fast.&lt;/p&gt;

&lt;p&gt;What does all that have to do with XAML, hex grids, and user controls? You would think I would know better. I start working on making a hexagon a user control and what bites me? Rounding errors! I should have known that rounding errors would cause problems.&lt;/p&gt;

&lt;p&gt;I started working on converting the shaded hexagon from my previous blog into a user control. I needed to work out the coordinates where to put each hexagon to create a hex grid. I created a column of hexagons. They looked good. I then added a second column, a third, and a fourth. Things looked great as you can see below.&lt;/p&gt;

&lt;a href="http://1.bp.blogspot.com/_Qg-uhnOHTis/Sf91ux7MjPI/AAAAAAAAABA/M75Q3dhWAVo/s1600-h/hexgirdroundingerrors1.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 200px; height: 104px;" src="http://1.bp.blogspot.com/_Qg-uhnOHTis/Sf91ux7MjPI/AAAAAAAAABA/M75Q3dhWAVo/s200/hexgirdroundingerrors1.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5332109930366012658" /&gt;&lt;/a&gt;

&lt;p&gt;Then I zoomed in a bit. Then I noticed that the hexagons did not always touch. I immediately knew the problem: rounding errors. You can see that below.&lt;/p&gt;

&lt;a href="http://2.bp.blogspot.com/_Qg-uhnOHTis/Sf92OpFG2GI/AAAAAAAAABI/9zvKgSbysbg/s1600-h/hexgirdroundingerrors2.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 200px; height: 118px;" src="http://2.bp.blogspot.com/_Qg-uhnOHTis/Sf92OpFG2GI/AAAAAAAAABI/9zvKgSbysbg/s200/hexgirdroundingerrors2.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5332110477747476578" /&gt;&lt;/a&gt;



&lt;p&gt;Hexagons tile the plane. Unfortunately you cannot tile them in XAML because you can only tile using simple rectangular patterns. I could use more precision. That would make the problem less likely to appear. The other option is just to make the hexagon grid as a series of polygons; each one calculated using as much accuracy as possible. You can see that below.&lt;/p&gt;


&lt;a href="http://3.bp.blogspot.com/_Qg-uhnOHTis/Sf92bM75zNI/AAAAAAAAABQ/UF9TpMDwYXo/s1600-h/hexgirdroundingerrors3.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 200px; height: 128px;" src="http://3.bp.blogspot.com/_Qg-uhnOHTis/Sf92bM75zNI/AAAAAAAAABQ/UF9TpMDwYXo/s200/hexgirdroundingerrors3.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5332110693530979538" /&gt;&lt;/a&gt;


&lt;p&gt;It looks like all is well with the hex grid. Until I made a simple change: I changed the stroke width to zero. You can see the result below.&lt;/p&gt;

&lt;a href="http://1.bp.blogspot.com/_Qg-uhnOHTis/Sf92rDXnUWI/AAAAAAAAABY/bf04Tc8-308/s1600-h/hexgirdroundingerrors4.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 200px; height: 124px;" src="http://1.bp.blogspot.com/_Qg-uhnOHTis/Sf92rDXnUWI/AAAAAAAAABY/bf04Tc8-308/s200/hexgirdroundingerrors4.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5332110965840761186" /&gt;&lt;/a&gt;




&lt;p&gt;Rounding errors are still visible. What does that mean? The short answer is you cannot expect to perfectly replicate a hexagon grid. &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7543977687602745925-3516847635725518245?l=jeffmcarthur.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jeffmcarthur.blogspot.com/feeds/3516847635725518245/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7543977687602745925&amp;postID=3516847635725518245' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/3516847635725518245'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/3516847635725518245'/><link rel='alternate' type='text/html' href='http://jeffmcarthur.blogspot.com/2009/05/rounding-error-are-important.html' title='Rounding Error Are an Important Consideration'/><author><name>Jeffrey McArthur</name><uri>http://www.blogger.com/profile/08114179926352904007</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_Qg-uhnOHTis/STbiKa5SGxI/AAAAAAAAAAM/xPpYa0jlVDM/S220/Jeff+Head.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_Qg-uhnOHTis/Sf91ux7MjPI/AAAAAAAAABA/M75Q3dhWAVo/s72-c/hexgirdroundingerrors1.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7543977687602745925.post-4194695815671350945</id><published>2009-05-03T20:34:00.000-07:00</published><updated>2009-05-03T21:15:36.918-07:00</updated><title type='text'>No Geometry Resources in Silverlight 2</title><content type='html'>&lt;p&gt;I wanted to create a hexagon grid.
There is a good article on how to draw a hexagon grid using C# code &lt;a href="http://www.codeproject.com/KB/graphics/hexagonal_part1.aspx"&gt;here.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I wanted to create my grid in XAML. I used Excel to do the calculations.
I also used Excel to generate the polygon points statement.
The simplest hexagon in XAML I could come up is
coded like this:&lt;/p&gt;
&lt;pre&gt;
&amp;lt;Canvas
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="480"
    Height="480"
&amp;gt;
    &amp;lt;Polygon Stroke="#000000" StrokeThickness="1" Points="0,35,20,0,60,0,80,35,60,69,20,69"/&amp;gt;
&amp;lt;/Canvas&amp;gt;
&lt;/pre&gt;
&lt;p&gt;That looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://3.bp.blogspot.com/_Qg-uhnOHTis/Sf5rDmeg0oI/AAAAAAAAAAw/5h7ylYPH1CI/s1600-h/hex.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 157px; height: 139px;" src="http://3.bp.blogspot.com/_Qg-uhnOHTis/Sf5rDmeg0oI/AAAAAAAAAAw/5h7ylYPH1CI/s200/hex.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5331816718465553026" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My next step was to set up a nice radial fill. I put the fill as a static resource.
The resulting code looks like this:&lt;/p&gt;
&lt;pre&gt;
&amp;lt;Canvas
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="480"
    Height="480"
&amp;gt;

    &amp;lt;Canvas.Resources&amp;gt;
        &amp;lt;RadialGradientBrush 
            x:Key="HexRadialFill"
            GradientOrigin="0.5,0.5" 
            Center="0.5,0.5" RadiusX="0.5" RadiusY="0.5"&amp;gt;
            &amp;lt;RadialGradientBrush.GradientStops&amp;gt;
                &amp;lt;GradientStop Color="LimeGreen" Offset="0" /&amp;gt;
                &amp;lt;GradientStop Color="Green" Offset="1" /&amp;gt;
            &amp;lt;/RadialGradientBrush.GradientStops&amp;gt;
        &amp;lt;/RadialGradientBrush&amp;gt;
    &amp;lt;/Canvas.Resources&amp;gt;

    &amp;lt;Polygon Stroke="#000000" StrokeThickness="1" Fill="{StaticResource HexRadialFill}"
        Points="0,35,20,0,60,0,80,35,60,69,20,69"/&amp;gt;
&amp;lt;/Canvas&amp;gt;
&lt;/pre&gt;
&lt;p&gt;The resulting image looks like:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://4.bp.blogspot.com/_Qg-uhnOHTis/Sf5rez7k6HI/AAAAAAAAAA4/ZGihI8knRE8/s1600-h/filledhex.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 163px; height: 130px;" src="http://4.bp.blogspot.com/_Qg-uhnOHTis/Sf5rez7k6HI/AAAAAAAAAA4/ZGihI8knRE8/s200/filledhex.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5331817185933584498" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I now planned on making the polygon a resource. Unfortunately you can't do that in
Silverlight 2. I looked into converting the polygon into a path and then putting that as a
geometry resource. Alas, Silverlight 2 does not allow geometry resources.&lt;/p&gt;

&lt;p&gt;I have a couple of options. I could make the hex a user or custom control. That would
allow code reuse. But at this time, I just want a hex grid. The quick and dirty way is
to just write some more macros in Excel and generate the entire grid as a bunch of
polygon statements. I could do that probably quicker than it took me to write this blog.
However, I am dedicated to quality. I would never allow a developer who worked for me to
hack out something quick and dirty like that. That means I need to create a user control
and code that up. It will take me longer to code up the user control. The advantage is the
resulting code will be reusable (even though I doubt I will reuse it).&lt;/p&gt;

&lt;p&gt;I now know what it was like to work for me. I am somewhat of a demanding manager. I want
things done the right way with no quick and dirty solutions. Now I can say I apply that
standard even to my own work.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7543977687602745925-4194695815671350945?l=jeffmcarthur.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jeffmcarthur.blogspot.com/feeds/4194695815671350945/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7543977687602745925&amp;postID=4194695815671350945' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/4194695815671350945'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/4194695815671350945'/><link rel='alternate' type='text/html' href='http://jeffmcarthur.blogspot.com/2009/05/no-geometry-resources-in-silverlight-2.html' title='No Geometry Resources in Silverlight 2'/><author><name>Jeffrey McArthur</name><uri>http://www.blogger.com/profile/08114179926352904007</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_Qg-uhnOHTis/STbiKa5SGxI/AAAAAAAAAAM/xPpYa0jlVDM/S220/Jeff+Head.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_Qg-uhnOHTis/Sf5rDmeg0oI/AAAAAAAAAAw/5h7ylYPH1CI/s72-c/hex.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7543977687602745925.post-1152065446980575674</id><published>2009-04-23T16:30:00.000-07:00</published><updated>2009-04-23T16:31:32.289-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='multi-boot'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows'/><category scheme='http://www.blogger.com/atom/ns#' term='System Commander'/><title type='text'>In Praise of Multi-Boot</title><content type='html'>I use a tool named System Commander to allow multi-booting. I recently ran into an interesting reason why multi-booting is very useful. I have heard comments that virtual machines make multi-booting almost unnecessary. I disagree.

I have a PC that I upgraded numerous times. It started out as a 486 to give you an idea of how long I have had this. I dont think anything is left of the original Gateway 486. As disk drives became less and less expensive I copied the images of the operating system over to new drives. I configured the system with three separate operating systems: Windows 2000, Windows XP, and Windows Server 2003. Using System Command the computer normally boots up into Windows XP but I have the option of booting up into old Windows 2000 or into Windows Server 2003. On a side note, when I boot up Windows 2003 I then run VMware server and have several VMs.

Sometime last summer, the sound out of the system started to act a little strange. There were pops, clicks, and stutters when playing music on Windows XP. I believe two different things causes issues with the sound system. First the sound card may have started to die. Second, one of Window XP innumerable updates may have cause the problem.

True to form, the sound completely died. I swapped out the sound card with another slightly different one. After reinstalling the drivers on all three operating systems, I have great sound on two of them: Windows 2000 and Windows Server 2003. But Windows XP still has pops, clicks, and stutters.

This means the problem is not with the sound card, but with Windows XP. It does not solve the problem, but it eliminates one possibility. Besides being able to switch operating systems, System Commander has the ability to repartition many disk formats. 

It is interesting that only Windows XP is affected. I considered installing Windows Vista. But I did not have the disk space.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7543977687602745925-1152065446980575674?l=jeffmcarthur.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jeffmcarthur.blogspot.com/feeds/1152065446980575674/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7543977687602745925&amp;postID=1152065446980575674' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/1152065446980575674'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/1152065446980575674'/><link rel='alternate' type='text/html' href='http://jeffmcarthur.blogspot.com/2009/04/in-praise-of-multi-boot.html' title='In Praise of Multi-Boot'/><author><name>Jeffrey McArthur</name><uri>http://www.blogger.com/profile/08114179926352904007</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_Qg-uhnOHTis/STbiKa5SGxI/AAAAAAAAAAM/xPpYa0jlVDM/S220/Jeff+Head.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7543977687602745925.post-6373030468163268217</id><published>2009-04-20T17:51:00.000-07:00</published><updated>2009-04-20T17:54:40.950-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Campaign Cartographer'/><category scheme='http://www.blogger.com/atom/ns#' term='XAML'/><category scheme='http://www.blogger.com/atom/ns#' term='Silverlight'/><category scheme='http://www.blogger.com/atom/ns#' term='Corel Draw'/><category scheme='http://www.blogger.com/atom/ns#' term='Illustrator'/><category scheme='http://www.blogger.com/atom/ns#' term='Expression Blend'/><title type='text'>Converting Campaign Cartographer Files to XAML</title><content type='html'>ProFantasy created a program named Campaign Cartographer. The program allows the quick creation of very high quality maps for role playing type of games. I was working on a logo for the company I am trying to start. I wanted to create a Silverlight XAML file for the logo. I knew that Campaign Cartographer could quickly and easily create a piece of the Logo.

Now for the challenges in getting that file into XAML. Campaign Cartographer has only a limited number of vector output options. I could easily create a bitmapped graphic in a variety of formats, but I wanted to stay in the vector space.

The logical place to start is as a Windows Metafile (.wmf or .emf). I exported the metafile and tried using one of the freeway tools EMFtoXAML. This produces basically produces an empty file. EMFtoXAML does not support any of the drawing commands used by Campaign Cartographer.

I then tried reading the .emf file into Adobe Illustrator CS 1 (the most recent version I own). The result is very low quality. My next step was Corel Draw 12 (the most recent version I own). Again, the result was awful. I gave up on .emf files.

Now to try another vector format: AutoCad .dxf. Now the fun begins. The current release of Campaign Cartographer is version 3. On my system, Campaign Cartographer 3 crashes when trying to export a .dxf. I then fire up an old PC that has Campaign Cartographer version 2 installed. This program exported the DXF without problem.

Then went back to Adobe Illustrator CS 1 to try and import the .dxf file. Again, Adobe Illustrator did not render the import usable. My next step was back to Corel Draw 12. Corel Draw 12 imports the .dxf. The result of the import into Corel Draw is not perfect. The import removes most but not all of the color. At least the outline is clean. Corel Draw can export an Adobe Illustrator file or .ai file. 

I installed the preview version of Expression Blend 3.0 from Microsoft. Expression Blend 3.0 is supposed to be able to import Adobe Illustrator files and create XAML. I fired up Expression Blend and created a Silverlight project. Expression Blend disables the menu options to import an Adobe Illustrator file when you create a Silverlight project. After fumbling around for a while I tried creating a WPF project in Expression Blend. That allows importing Adobe Illustrator files. I did some searching on the web, and nothing mentions you can only import Adobe Illustrator into WPF projects.

I tried importing the Adobe Illustrator file created by Corel Draw 12. Expression Blend 3.0 Preview says it cannot understand the file and cannot import it. I then go back to Adobe Illustrator. I open up the file created by Corel Draw in Adobe Illustrator and save the file back as another .ai file. It is interesting to note the Adobe Illustrator's default name for the file adds the word "[Converted]" to the file name.

I open Expression Blend 3.0 back up to my WPF project. Finally I can import the .ai file and the image appears in Expression Blend. The colors are gone, but at least I have the XAML file I can work with.

I hope that someday ProFantasy will add the ability to export data directly into XAML.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7543977687602745925-6373030468163268217?l=jeffmcarthur.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jeffmcarthur.blogspot.com/feeds/6373030468163268217/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7543977687602745925&amp;postID=6373030468163268217' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/6373030468163268217'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/6373030468163268217'/><link rel='alternate' type='text/html' href='http://jeffmcarthur.blogspot.com/2009/04/converting-campaign-cartographer-files.html' title='Converting Campaign Cartographer Files to XAML'/><author><name>Jeffrey McArthur</name><uri>http://www.blogger.com/profile/08114179926352904007</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_Qg-uhnOHTis/STbiKa5SGxI/AAAAAAAAAAM/xPpYa0jlVDM/S220/Jeff+Head.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7543977687602745925.post-5675737537875386498</id><published>2009-04-08T07:34:00.000-07:00</published><updated>2009-04-08T07:35:45.240-07:00</updated><title type='text'>Windows Forms versus Web-Based Technology</title><content type='html'>A friend asked a question: "I have a question...curious about what you know about web-based system architecture design.  Specifically, use of Windows Forms (.net framework) versus Frames Technology."

The short answer to your question is web-based systems run inside a browser, and windows forms based applications run as applications on your PC.

But things are a bit more complicated. Web-based systems use a variety of standards: HTML, XHTML, XML, and CSS. Developing a web based application requires testing on a variety of browsers (Internet Explorer, FireFox, etc.). You can access a web-based systems can from mobile devices like a BlackBerry, iPhone, and so on. Because they run in a browser, web based application also run on Macs and other operating systems besides Windows. In general, web based systems do not need to be installed on the computer. To run a web based application you just open up the browser and point it to the URL for the application. The downside is that Web-based systems have limitations on what data they can store or access on your local computer. A well designed web based application allows changing the "skin" of the application easily. Someone can change the colors, fonts, or layout used in an application without the need to recompile or reinstall the entire program. You must have a connection to the network for a web-based application to run. The phrase "software-as-a-service" or SAAS is usually associated with web based applications. Web-based applications run from a server. Changing the application on the server changes the application for every user at the same time.

Windows forms based applications only run on a PC. You must install windows forms based applications. This means the application can take full advantage of any hardware you have on your PC. The application can access and store data on your local hard drive. To change the fonts, colors, or layout of the application usually required a new build of the application and a new install. (There were tools to support "skins".)

Things are ever more complicated. Technology continues to innovate. Windows forms technology is old. Microsoft replaced Windows forms with Windows Presentation Foundation or WPF. Another name for this technology is Silverlight. WPF makes it easy to change the graphics, layout, fonts, and colors used by an application. This technology allows developers to use a component based development methodology. Developers just click and drop the components they need on the form and connect them. Another name for component based development is rapid application development or RAD. Customization of the application to make it look pretty no longer requires a developer. By the way, this was a huge issue at one company I worked for. I remember one project where the developer finished the functionality of the application in about two weeks. Then the developer spent the next nine months continually changing the colors, fonts, and layout to make the application pretty enough. (I used to get into nasty arguments about the time wasted on changing the colors, fonts, and layout.) Silverlight applications run inside most browsers. 

The server (or servers) must be up and running twenty four hours a day, seven days a week, three hundred and sixty five days a year for Web-based or Software-as-a-service based applications. If the server or network goes down, everyone is down. You install windows based applications on each PC. If the PC is working the application usually works. However, if the application requires access to a database, then the application only works if the database server is up and running. The biggest headache to windows based applications is the release of new versions of the software.

Technology continues to change. Perhaps the best example is the game World of Warcraft. This is an application you install on your local PC that talks to a set of servers. World of Warcraft automatically installs new versions when you log in. The game wont run if you dont have an Internet connection. World of Warcraft uses your graphics card to the max. Performance of the game is generally limited by your PC and not by the server. This does put a bit of a strain on some network connections.

If you need to make the decision on which technology the first question is: "will the individual computers always have a connection to the network and/or Internet?" If the answer is "no", then in general you want to stay away from a web-based solution. (I did manage a project that embedded a web server inside the application, but that is a complicated solution.) If the answer to that question is "yes", then you need to think about the type of computers each person who runs the application has. If you have a combination of PCs and Macs, then you should go with a web-based solution. If one of the stakeholders places the esthetics of the application very high, then go with a web-based solution. If you plan on changing the application frequently, it is easier to change a web-based solution. On the other hand, if you need to get performance out of the local PC, go with a windows based solution.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7543977687602745925-5675737537875386498?l=jeffmcarthur.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jeffmcarthur.blogspot.com/feeds/5675737537875386498/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7543977687602745925&amp;postID=5675737537875386498' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/5675737537875386498'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/5675737537875386498'/><link rel='alternate' type='text/html' href='http://jeffmcarthur.blogspot.com/2009/04/windows-forms-versus-web-based.html' title='Windows Forms versus Web-Based Technology'/><author><name>Jeffrey McArthur</name><uri>http://www.blogger.com/profile/08114179926352904007</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_Qg-uhnOHTis/STbiKa5SGxI/AAAAAAAAAAM/xPpYa0jlVDM/S220/Jeff+Head.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7543977687602745925.post-2668017493083014668</id><published>2009-01-31T11:37:00.000-08:00</published><updated>2009-01-31T11:38:56.363-08:00</updated><title type='text'>Lack of Pride in your Work</title><content type='html'>I recently downloaded a small program from an open source repository. I took a look at the sources and was shocked. With the exception of some commented out code, the IDE generated all the comments. There was not even a header on the files showing that the source code was under an open source license or giving credit to the original author.

I have experience working with poorly written and/or poorly commented code. I admit that I have written some code like that. But I also have written some code that is easy to maintain and is well commented. Early in my career I learned from some excellent teachers. I still have some of the papers that Nelson Beebe wrote about writing portable software almost thirty years ago. Brad Davis taught me a lot when I worked at the University of Utah. I still have some code I wrote way back when that still runs. The code I wrote then did not have a lot of comments, but the naming conventions and structure make it easy to read and understand. If I wrote that code today, I would use some different approaches, but then programming has changed a lot over the last twenty to thirty years.

I know the quality of my twenty year old code is better than the source code to the small program I downloaded. Part of the idea of open source is pride in your work. How can a developer lack the pride to polish their code before they publish it to an open source repository? If you publish your code you expect others to read your code. Don't you clean up your home before you invite visitors in? You should do the same thing with your code. Clean and polish your code before you publishing it. Take pride in doing a good job. There is a saying, "a job worth doing is worth doing well."

One of the things I require of the people that work for me is that they do a good job that they can be proud of. I know a lot of companies rush to get software out the door. This is particularly true in startups. Get it working is the mantra. But that hurts you in the end. You create products that are not maintainable. I establish the processes and procedure to take an immature software organization and create a predictable, sustainable, measurable, and managed team that delivers quality products on time and on budget.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7543977687602745925-2668017493083014668?l=jeffmcarthur.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jeffmcarthur.blogspot.com/feeds/2668017493083014668/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7543977687602745925&amp;postID=2668017493083014668' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/2668017493083014668'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/2668017493083014668'/><link rel='alternate' type='text/html' href='http://jeffmcarthur.blogspot.com/2009/01/lack-of-pride-in-your-work.html' title='Lack of Pride in your Work'/><author><name>Jeffrey McArthur</name><uri>http://www.blogger.com/profile/08114179926352904007</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_Qg-uhnOHTis/STbiKa5SGxI/AAAAAAAAAAM/xPpYa0jlVDM/S220/Jeff+Head.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7543977687602745925.post-7216798816169931096</id><published>2008-12-22T02:11:00.000-08:00</published><updated>2008-12-22T02:15:50.313-08:00</updated><title type='text'>Adventures with Interactive Fiction</title><content type='html'>&lt;p&gt;Wikipedia defines &lt;a href="http://en.wikipedia.org/wiki/Interactive_fiction"&gt;Interactive Fiction&lt;/a&gt; as "software simulating environments in which players use text commands to control characters and influence the environment."&lt;/p&gt;

&lt;p&gt;I played Adventure, the Colossal Cave and numerous Scott Adams adventures. I looked at currently available systems used to create interactive fiction. There are a variety of mature systems that allow easy creation of complex adventures. I read through the user manuals and much of the technical documentation on several different systems. Then I read the IF Authoring System Developer's Guide by Peer Schaefer. I then decided to try and create my own adventure system. Peer Schaefer recommended, "So, you want to write an Interactive Fiction authoring system? Ok, here's my advice: don't do it." That is interesting advice. Peer Schaefer mentioned two authoring systems that used XML as their base: AAS and Aiee. I have a tremendous amount of experience with XML. It appears both AAS and Aiee are abandoned. No one has done any work with either since 2004. I contacted one of the authors. The authors of AAS never released the source code. It appears that the original source code for AAS may be lost. I tried to contact the author of Aiee. I received no response.&lt;/p&gt;

&lt;p&gt;Of the two, AAS and Aiee, AAS had better documentation. AAS also has a development environment. I tried creating a game with AAS. I immediately ran into problems. AAS did not fully implement all the documented functionality. For example, the test to see if a container is open does not work. Fortunately there are eleven AAS games available. After reading through the XML sources I was able to figure a work around. I used AAS to create an entry into the &lt;a href="http://www.avventuretestuali.com/orgc/orgc2008_eng"&gt;One Room Game Competition 2008.&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7543977687602745925-7216798816169931096?l=jeffmcarthur.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jeffmcarthur.blogspot.com/feeds/7216798816169931096/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7543977687602745925&amp;postID=7216798816169931096' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/7216798816169931096'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/7216798816169931096'/><link rel='alternate' type='text/html' href='http://jeffmcarthur.blogspot.com/2008/12/adventures-with-interactive-fiction.html' title='Adventures with Interactive Fiction'/><author><name>Jeffrey McArthur</name><uri>http://www.blogger.com/profile/08114179926352904007</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_Qg-uhnOHTis/STbiKa5SGxI/AAAAAAAAAAM/xPpYa0jlVDM/S220/Jeff+Head.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7543977687602745925.post-765170565090478157</id><published>2008-12-18T20:37:00.001-08:00</published><updated>2008-12-18T20:37:59.511-08:00</updated><title type='text'>Technology Professionals Networking Group (TPNG) Meeting</title><content type='html'>I attended the Technology Professionals Networking Group (TPNG) meeting tonight. The speaker was Kimberle Levin, president and CEO of Teknuko. Ms. Levin talked about “schmoozing”. It was an interesting and lively presentation. She mentioned that little things matter a lot. For example, at a networking opportunity you should have your name tag on the right. When you shake hands with someone their eyes will follow up your arm to your name tag. I admit, I never thought of that or ever heard anyone mention why you would wear your name tag on one side or the other.

Ms. Levin gave several examples from her personal life how “schmoozing” and networking worked to her advantage. She gave some interesting examples of how to correctly shake someone’s hand, and how not to shake someone’s hand. All in all, it was a fascinating presentation. I hope to go through the slides to her presentation in detail.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7543977687602745925-765170565090478157?l=jeffmcarthur.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jeffmcarthur.blogspot.com/feeds/765170565090478157/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7543977687602745925&amp;postID=765170565090478157' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/765170565090478157'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/765170565090478157'/><link rel='alternate' type='text/html' href='http://jeffmcarthur.blogspot.com/2008/12/technology-professionals-networking.html' title='Technology Professionals Networking Group (TPNG) Meeting'/><author><name>Jeffrey McArthur</name><uri>http://www.blogger.com/profile/08114179926352904007</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_Qg-uhnOHTis/STbiKa5SGxI/AAAAAAAAAAM/xPpYa0jlVDM/S220/Jeff+Head.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7543977687602745925.post-159402021594944920</id><published>2008-12-11T22:49:00.000-08:00</published><updated>2008-12-11T23:30:10.299-08:00</updated><title type='text'>Philadelphia-Area Software Process Improvement Network Meeting</title><content type='html'>I attended the Philadelphia-Area SPIN (Software Process Improvement Network) meeting tonight. The topic was: “How can we measure the value of IT?” Michael Harris from David Consulting Group (www.davidconsultinggroup.com) made the presentation.

The phrase “beauty is in the eye of the beholder” implies that what one person things is beautiful another may not. Value is similar. This leads to a similar phrase, “value is in the eye of the beholder”. A developer may value the beauty of a well crafted program. But unless the program generates revenue for the company, management may not see the value or beauty in the program.

Mr. Harris brought up an interesting point: value has a time component. For example, if an information technology organization delivers a project that is late by only ten percent, the market value of the project may actually be fifty percent less. I like the analogy of going to a restaurant. I value restaurants that quickly seat and serve you. If a restaurant takes ninety minutes to bring me a meal, no matter how good the meal is, I will not go back to that restaurant. The meal decreased in value the longer it takes to prepare it. The same is true with software development. If you take too long to create the software the market may have found a different solution.

The decreasing value over time is the reason for many innovations in information technology. For example, we want a new computer because it is faster than the old one. The value of the computer has decreased because a faster model now exists. 

I believe our current financial crisis is based on the false premise that homes should increase in value over time. Why should a home increase in value? The plumbing does not get better over time. The furnace and water heaters do not improve with age. Businesses depreciate the cost of buildings and equipment over time because they are worth less as they age. 

Getting back to the topic of the meeting, Mr. Harris described a variety of standard financial methods that anyone in management in IT should know and understand. Mr. Harris stated the best method was Real Option Valuation. I need to dig a bit deeper into this methodology. I added a book to my wish list: “20/20 Foresight: Crafting Strategy in an Uncertain World” by Hugh Courtney.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7543977687602745925-159402021594944920?l=jeffmcarthur.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jeffmcarthur.blogspot.com/feeds/159402021594944920/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7543977687602745925&amp;postID=159402021594944920' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/159402021594944920'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/159402021594944920'/><link rel='alternate' type='text/html' href='http://jeffmcarthur.blogspot.com/2008/12/philadelphia-area-software-process.html' title='Philadelphia-Area Software Process Improvement Network Meeting'/><author><name>Jeffrey McArthur</name><uri>http://www.blogger.com/profile/08114179926352904007</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_Qg-uhnOHTis/STbiKa5SGxI/AAAAAAAAAAM/xPpYa0jlVDM/S220/Jeff+Head.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7543977687602745925.post-226268750016303952</id><published>2008-12-10T21:48:00.000-08:00</published><updated>2008-12-10T21:53:01.299-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><title type='text'>The Parable of the Two Programmers</title><content type='html'>David G. Wiseman created list of Stories for a Computer Audience &lt;a href="http://www.csd.uwo.ca/staff/magi/personal/humour/Computer_Audience.html"&gt;Computer Audience&lt;/a&gt;.

This archive contains many of the (in)famous stories about computers from over the years. One of my favorites is &lt;a href="http://www.csd.uwo.ca/~magi/personal/humour/Computer_Audience/The%20Parable%20of%20the%20Two%20Programmers.html"&gt;The Parable of the Two Programmers.&lt;/a&gt; I you have never read this story, it is a must read.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7543977687602745925-226268750016303952?l=jeffmcarthur.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jeffmcarthur.blogspot.com/feeds/226268750016303952/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7543977687602745925&amp;postID=226268750016303952' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/226268750016303952'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/226268750016303952'/><link rel='alternate' type='text/html' href='http://jeffmcarthur.blogspot.com/2008/12/he-parable-of-two-programmers.html' title='The Parable of the Two Programmers'/><author><name>Jeffrey McArthur</name><uri>http://www.blogger.com/profile/08114179926352904007</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_Qg-uhnOHTis/STbiKa5SGxI/AAAAAAAAAAM/xPpYa0jlVDM/S220/Jeff+Head.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7543977687602745925.post-8167171963717380156</id><published>2008-12-10T21:22:00.000-08:00</published><updated>2008-12-10T21:24:01.439-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='TENG'/><category scheme='http://www.blogger.com/atom/ns#' term='personality testing'/><category scheme='http://www.blogger.com/atom/ns#' term='Philadelphia'/><title type='text'>Philadelphia Technology Executives Networking Group (TENG)</title><content type='html'>I attended a meeting of the Philadelphia Technology Executives Networking Group (TENG). This was a great opportunity to meet other technology executives. It was a small get together of about twelve at a local restaurant. TENG helps those “in transition” find new positions.

One of the interesting topics discussed tonight was personality testing. Today, I took an assessment test for a position I applied for. The test had several parts including a personality test. Several other people at the TENG meeting have taken similar tests. Everyone at the meeting who had been required to take a personality test for a job didn’t get the job. This was a small sample, only a couple of people. One person mentioned they had a first, second, and third interview before taking the personality test. The hiring company did not offer a job after three interviews. Was the result of the personality test the reason? Companies never answer that question. The discussion about why personality test could be necessary was interesting. I can see how they could help, I just wonder about the cost effectiveness of personality testing. I hope I buck the trend and get offered the job.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7543977687602745925-8167171963717380156?l=jeffmcarthur.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jeffmcarthur.blogspot.com/feeds/8167171963717380156/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7543977687602745925&amp;postID=8167171963717380156' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/8167171963717380156'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/8167171963717380156'/><link rel='alternate' type='text/html' href='http://jeffmcarthur.blogspot.com/2008/12/philadelphia-technology-executives.html' title='Philadelphia Technology Executives Networking Group (TENG)'/><author><name>Jeffrey McArthur</name><uri>http://www.blogger.com/profile/08114179926352904007</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_Qg-uhnOHTis/STbiKa5SGxI/AAAAAAAAAAM/xPpYa0jlVDM/S220/Jeff+Head.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7543977687602745925.post-8593044051397123463</id><published>2008-12-10T20:58:00.000-08:00</published><updated>2008-12-10T21:00:23.509-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Entrepreneur'/><category scheme='http://www.blogger.com/atom/ns#' term='marketing'/><category scheme='http://www.blogger.com/atom/ns#' term='Philadelphia'/><title type='text'>Entrepreneurs' Forum of Greater Philadelphia Meeting</title><content type='html'>I attended Entrepreneurs' Forum of Greater Philadelphia Meeting last night. The topic was The Road Ahead, Surviving and Thriving in Today's Economy. This is the second time I have attended an Entrepreneurs' Forum meeting. The meeting is a great place to meet and network with others with an interest in entrepreneurship. I met several interesting people including someone from the marketing department of a local radio station.

The meeting focused on the affects of the market on entrepreneurship. One of the panelists mentioned a book, Mastering the Rockefeller Habits: What You Must Do to Increase the Value of Your Growing Firm, by Verne Harnish. I remember years ago someone mentioning the Rockefeller Habits. The copyright of the book is 2002. I added it to my wish list on Amazon.

One of the panelists mentioned the importance of focusing on strategy and not on tactics. In military terms strategy is the big picture. Tactics focus on the current circumstances and situation. In today’s economy, a successful organization must keep their focus on the big picture. The current economic situation requires attention but we must not lose the focus on the objectives.

Tracking is imperative. How can you know if your marketing is effective without tracking the success? If you make a change to your website how did that affect your page views? You need to test the results to see if they meet expectation. Few can afford the luxury of making a significant change in their marketing with having a reason. Predictive modeling should help estimate the effect of a change. To close the loop you need to compare the actual results with the predictions. If your results don’t match with the predictions can you make a tweak to help improve the results? You must base your decisions on real data and metrics, not on gut feel.

An organization needs a high return on marketing activities. If you spent a thousand dollars on marketing to win a thousand dollars in new sales the marketing was a failure. Marketing dollars should have at least a tenfold return on investment. Right now, Internet marketing is the greatest value for the money.

Purple Cow: Transform Your Business by Being Remarkable by Seth Godin is another book mentioned by the panel. Organizations must become remarkable to succeed. You must generate buzz and stand out from the crowd.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7543977687602745925-8593044051397123463?l=jeffmcarthur.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jeffmcarthur.blogspot.com/feeds/8593044051397123463/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7543977687602745925&amp;postID=8593044051397123463' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/8593044051397123463'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/8593044051397123463'/><link rel='alternate' type='text/html' href='http://jeffmcarthur.blogspot.com/2008/12/entrepreneurs-forum-of-greater.html' title='Entrepreneurs&apos; Forum of Greater Philadelphia Meeting'/><author><name>Jeffrey McArthur</name><uri>http://www.blogger.com/profile/08114179926352904007</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_Qg-uhnOHTis/STbiKa5SGxI/AAAAAAAAAAM/xPpYa0jlVDM/S220/Jeff+Head.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7543977687602745925.post-1721637226317239916</id><published>2008-12-04T16:29:00.000-08:00</published><updated>2008-12-04T16:31:13.342-08:00</updated><title type='text'>Google Friend Connect</title><content type='html'>I received acceptance for my website to use Google Friend Connect. I applied in May. Just received approval today.

Back in May, I was excited by the idea of adding Google Friend Connect. Google took a long time to approve my site. Seven months later I had all but forgot about it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7543977687602745925-1721637226317239916?l=jeffmcarthur.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jeffmcarthur.blogspot.com/feeds/1721637226317239916/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7543977687602745925&amp;postID=1721637226317239916' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/1721637226317239916'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/1721637226317239916'/><link rel='alternate' type='text/html' href='http://jeffmcarthur.blogspot.com/2008/12/google-friend-connect.html' title='Google Friend Connect'/><author><name>Jeffrey McArthur</name><uri>http://www.blogger.com/profile/08114179926352904007</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_Qg-uhnOHTis/STbiKa5SGxI/AAAAAAAAAAM/xPpYa0jlVDM/S220/Jeff+Head.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7543977687602745925.post-470498738544635432</id><published>2008-12-03T11:43:00.000-08:00</published><updated>2008-12-03T11:44:44.036-08:00</updated><title type='text'>Trying out Blogging</title><content type='html'>This is my first blog post. Nothing intereseting yet.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7543977687602745925-470498738544635432?l=jeffmcarthur.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jeffmcarthur.blogspot.com/feeds/470498738544635432/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7543977687602745925&amp;postID=470498738544635432' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/470498738544635432'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7543977687602745925/posts/default/470498738544635432'/><link rel='alternate' type='text/html' href='http://jeffmcarthur.blogspot.com/2008/12/trying-out-blogging.html' title='Trying out Blogging'/><author><name>Jeffrey McArthur</name><uri>http://www.blogger.com/profile/08114179926352904007</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_Qg-uhnOHTis/STbiKa5SGxI/AAAAAAAAAAM/xPpYa0jlVDM/S220/Jeff+Head.jpg'/></author><thr:total>0</thr:total></entry></feed>
