<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="http://feeds.feedburner.com/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/"><id>tag:blogger.com,1999:blog-35928092</id><updated>2008-11-12T11:40:11.824-05:00</updated><title type="text">The Macadamian Files</title><subtitle type="html">Discussing the nuts and bolts of software development</subtitle><link rel="alternate" type="text/html" href="http://thefiles.macadamian.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default?start-index=26&amp;max-results=25" /><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://thefiles.macadamian.com/atom.xml" /><author><name>Jason Mawdsley</name><uri>http://www.blogger.com/profile/12753716679505402680</uri><email>jason@macadamian.com</email></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>43</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><link rel="self" href="http://feeds.feedburner.com/macadamian/thefiles" type="application/atom+xml" /><entry><id>tag:blogger.com,1999:blog-35928092.post-7803744594165699629</id><published>2008-11-12T11:25:00.006-05:00</published><updated>2008-11-12T11:40:11.875-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="rest" /><category scheme="http://www.blogger.com/atom/ns#" term="twitter" /><title type="text">The Anti-social web - Twitter for the socially inept</title><content type="html">Twitter was mentioned during Macadamian's corporate blogging presentation. "Useless! Bah! Humbug!" were the first thoughts to enter my head. Then the speaker pointed out that corporate bloggers should strive to see the positive side of any situation, and I figured making Twitter useful to a neo-Luddite was a good challenge; there must be an itch to scratch here, right?&lt;br /&gt;&lt;br /&gt;All I knew about Twitter was that people think it's slow, and it's written in Ruby (on Rails.) After exploring a little more, I found out that it can provide private Atom feeds of your messages, and exposes a REST API (ooh, new, shiny!) That was enough to get me coding.&lt;br /&gt;&lt;br /&gt;To keep things simple I decided to be boring and test out Twitter using Ruby (normally, I plan epic posts with 5 different languages, communicating through at least 2 protocols... and a database for no good reason.) The process I followed was:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Install Ruby (one-click installer)&lt;/li&gt;&lt;li&gt;In the Gems package manager: gem install &lt;a href="http://rest-client.heroku.com/rdoc/"&gt;rest-client&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Install the &lt;a href="http://rubyeclipse.sourceforge.net/"&gt;Ruby Development Tools&lt;/a&gt; for Eclipse&lt;/li&gt;&lt;li&gt;Read the &lt;a href="http://apiwiki.twitter.com/REST+API+Documentation#DirectMessageMethods"&gt;Twitter API&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;require 'date'&lt;br /&gt;require 'rest_client'&lt;br /&gt;require 'rexml/document'&lt;br /&gt;&lt;br /&gt;username = "your_twitter_id_here"&lt;br /&gt;password = "your_twitter_password_here"&lt;br /&gt;&lt;br /&gt;twitter = RestClient::Resource.new 'http://%s:%s@twitter.com' % [ username, password ]&lt;br /&gt;&lt;br /&gt;# Send a message to twitter&lt;br /&gt;result = twitter['statuses/update.xml'].post(&lt;br /&gt;   :status =&gt; "This is your computer.  You have no life as of %s" % DateTime.now()&lt;br /&gt;)&lt;br /&gt;# print result&lt;br /&gt;&lt;br /&gt;timelineXML = twitter['statuses/user_timeline.xml'].get({ :count =&gt; 5 });&lt;br /&gt;&lt;br /&gt;# Make the XML usable&lt;br /&gt;# (Use XmlSimple for even easier handling)&lt;br /&gt;timeline = REXML::Document.new(timelineXML)&lt;br /&gt;&lt;br /&gt;# Display the text element of every status returned by the service&lt;br /&gt;# (print timelineXML to learn more about the structure of the result.)&lt;br /&gt;puts "%s's timeline:" % username&lt;br /&gt;timeline.elements.each('statuses/status/text') { |message|&lt;br /&gt;   puts message.text&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;As Twitter &lt;a href="http://apiwiki.twitter.com/REST+API+Documentation#RateLimiting"&gt;restricts you to 70 calls per hour&lt;/a&gt;, it's a good job Ruby (on REST) made this so easy.  REST is a nice change from the usual URL gobbledygook that frameworks throw up - I can't wait to try it out in &lt;a href="http://struts.apache.org/2.x/docs/rest-plugin.html"&gt;Struts2&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;So, what can people with no interest in socializing do with Twitter?&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Free yourself from your desk by monitoring that 45 minute long J2EE build from &lt;a href="http://twitterforiphone.com/"&gt;your iPhone&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Monitor your computers by receiving disk capacity warnings, CPU performance reports, and IP address changes&lt;/li&gt;&lt;li&gt;Find out when &lt;a href="http://tech.shantanugoel.com/2008/05/14/keep-tab-on-home-security-with-a-webcam-and-twitter.html"&gt;someone is breaking into your home&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Know when &lt;a href="http://www.engadget.com/2008/02/25/diy-kit-lets-houseplants-twitter-when-they-need-water/"&gt;your plants need to be watered&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Search for signs of life in the &lt;a href="http://www.p2pnet.net/story/16101"&gt;Mars lander&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;One final note, until &lt;a href="http://apiwiki.twitter.com/REST+API+Documentation#Authentication"&gt;the authentication framework is more robust&lt;/a&gt;, don’t rely on anything you twit staying private.&lt;img src="http://feeds.feedburner.com/~r/macadamian/thefiles/~4/450878697" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/7803744594165699629/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=35928092&amp;postID=7803744594165699629" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/7803744594165699629" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/7803744594165699629" /><link rel="alternate" type="text/html" href="http://thefiles.macadamian.com/2008/11/anti-social-web-twitter-for-socially.html" title="The Anti-social web - Twitter for the socially inept" /><author><name>Gord. P</name><uri>http://www.blogger.com/profile/10684846302006538110</uri><email>noreply@blogger.com</email></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35928092.post-5878686279857402690</id><published>2008-10-29T00:41:00.005-04:00</published><updated>2008-10-29T10:02:44.011-04:00</updated><title type="text">Breadth-First Coding</title><content type="html">&lt;span style="font-size:130%;"&gt;&lt;span style="font-style: italic;"&gt;"Look Ma! I'm inventing my own buzzwords!"&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:180%;" &gt;The problem&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;A little while ago, some of us at &lt;a href="http://www.macadamian.com/"&gt;Macadamian&lt;/a&gt; held discussions on behaviors we would like to encourage among younger developers. One thing we agreed was that "stubbing" (coming up with methods containing as little code as possible, in order to stabilize the API interactions faster) was becoming a "lost art". And so we resolved to start encouraging "top-down development", as we were used to call it.&lt;br /&gt;&lt;br /&gt;So far, we've met with little success. Despite our explicit encouragements, it seems hard for people to adopt a "top-down" approach.&lt;br /&gt;&lt;br /&gt;And lately, I've been wondering: what if we're not communicating right? After all, "top-down" is a pretty generic term. After all, it's even used to describe &lt;a href="http://en.wikipedia.org/wiki/Top_down"&gt;an entire programming methodology&lt;/a&gt; which predates Object-Oriented Design. So perhaps some of the people in our teams are thinking: "&lt;span style="font-style: italic;"&gt;Of cours&lt;/span&gt;e I'm going from top to bottom, what are they complaining about!?"&lt;br /&gt;&lt;br /&gt;That's when I thought of something...&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:180%;" &gt;Mandatory flashback to the author's younger days&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Back at school, I followed this neat AI course which taught me some general problem-solving heuristics. Overall, it showed two ways to attack a problem by brute force: &lt;span style="font-style: italic;"&gt;breadth-first&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;depth-first&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Let's say we're looking for a file within a directory structure. A &lt;span style="font-style: italic;"&gt;depth-first&lt;/span&gt; approach will recursively explore each solution by first going to the lowest node possible. Only then will it work its way back up, before going down again.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://thefiles.macadamian.com/uploaded_images/DF-Tree-741487.png"&gt;&lt;img style="cursor: pointer; width: 320px; height: 200px;" src="http://thefiles.macadamian.com/uploaded_images/DF-Tree-741467.png" alt="Depth-First Search" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;A &lt;span style="font-style: italic;"&gt;breadth-first&lt;/span&gt; approach, on the other hand, would attempt to fully explore one level of nodes before jumping to the next one.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://thefiles.macadamian.com/uploaded_images/BF-Tree-756275.png"&gt;&lt;img style="cursor: pointer; width: 320px; height: 210px;" src="http://thefiles.macadamian.com/uploaded_images/BF-Tree-756269.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;For additional details, you check out &lt;a href="http://en.wikipedia.org/wiki/Breadth-first_search"&gt;breadth-first search&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Depth-first"&gt;depth-first search&lt;/a&gt; on Wikipedia (where I borrowed these graphs from).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:180%;" &gt;And so...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I'm beginning to think that younger developers show a natural tendency to code &lt;span style="font-style:italic;"&gt;depth-first&lt;/span&gt;. They pick a single feature/functionality/API call, then implement it down to the lowest level, at which point they consider to have a "valid iteration". Then they go back up a few levels, and start again. Doing things that way can make you feel good because you've added a lot of code, but it makes things harder to test, and might complicate future integration.&lt;br /&gt;&lt;br /&gt;We'd like people to try out &lt;span style="font-style:italic;"&gt;breadth-first coding&lt;/span&gt;, which would mean getting a wider range of partly-implemented methods in the early stages.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://upload.wikimedia.org/wikipedia/commons/4/46/Animated_BFS.gif"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 187px; height: 175px;" src="http://upload.wikimedia.org/wikipedia/commons/4/46/Animated_BFS.gif" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;First, you'd define the APIs of the first layer, providing a "bare-bone" implementation of each method. Then you'd define the second layer, once again with a minimal implementation, at which point you'd be able to properly implement the first layer. Repeat for each layer of implementation.&lt;br /&gt;&lt;br /&gt;So, as my first step, I'll start using the term "breadth-first" when talking about this approach. I'm hoping that by using this term instead of "top-down", I'll get a few "Huh? WTF?" responses, which may be just what we need in order to break some old habits...&lt;img src="http://feeds.feedburner.com/~r/macadamian/thefiles/~4/435475173" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/5878686279857402690/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=35928092&amp;postID=5878686279857402690" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/5878686279857402690" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/5878686279857402690" /><link rel="alternate" type="text/html" href="http://thefiles.macadamian.com/2008/10/breadth-first-coding.html" title="Breadth-First Coding" /><author><name>Gilles Duchesne</name><uri>http://www.blogger.com/profile/17000369075138803767</uri><email>noreply@blogger.com</email></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35928092.post-8080723372392435717</id><published>2008-09-12T09:28:00.004-04:00</published><updated>2008-09-12T09:59:03.465-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="web development" /><category scheme="http://www.blogger.com/atom/ns#" term="Win32" /><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint" /><category scheme="http://www.blogger.com/atom/ns#" term="code quality" /><category scheme="http://www.blogger.com/atom/ns#" term="c#" /><category scheme="http://www.blogger.com/atom/ns#" term="string conversion" /><title type="text">Bridge SharePoint - User Profiles and User Profile Properties (part 2 of 2)</title><content type="html">&lt;p&gt;As we have found out in part 1, SharePoint can manipulate data using the user profile management objects and can accept data from external sources. Using these two features apart we have two limited tools with limited usage, but using them together gives us a powerful, flexible and efficient method of storing and using data from any internal or external resource.&lt;br /&gt;&lt;br /&gt;It’s time to see this solution to our problems in action. &lt;/p&gt; &lt;p&gt;&lt;b&gt;Code example of getting/setting the profile property from a C# application&lt;/b&gt; &lt;/p&gt; &lt;p&gt;The concept is the same for any source of information (web services, web applications, etc.):&lt;br /&gt;Get the user’s profile-&amp;gt;Get the required profile property-&amp;gt;Get/Set profile property value &lt;/p&gt; &lt;p&gt;&lt;b&gt;Code example&lt;/b&gt;: (note that to access profile properties, this code must run with elevated privileges)&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;string &lt;/span&gt;value;&lt;br /&gt;&lt;span style="color:blue;"&gt;try&lt;br /&gt;&lt;/span&gt;{&lt;br /&gt; SPSecurity.RunWithElevatedPrivileges(&lt;span style="color:blue;"&gt;delegate&lt;/span&gt;()&lt;br /&gt; {&lt;br /&gt;  &lt;br /&gt;     &lt;span style="color:green;"&gt;// Change the site address for different deployment environments&lt;br /&gt;     // Note: WIN2003STD is a place holder for your environment, usually your server name&lt;br /&gt;     &lt;/span&gt;SPSite site = &lt;span style="color:blue;"&gt;new &lt;/span&gt;SPSite(&lt;span style="color: rgb(163, 21, 21);"&gt;"http://WIN2003STD/"&lt;/span&gt;);&lt;br /&gt;     SPWeb web = site.OpenWeb();&lt;br /&gt;&lt;br /&gt;     &lt;span style="color:green;"&gt;// Get the profile manager object for the site&lt;br /&gt;     &lt;/span&gt;UserProfileManager profileManager = &lt;span style="color:blue;"&gt;new &lt;/span&gt;UserProfileManager(ServerContext.GetContext(site));&lt;br /&gt;&lt;br /&gt;     &lt;span style="color:green;"&gt;// Use the username from the User Information Item to get the full profile of an user&lt;br /&gt;     &lt;/span&gt;UserProfile user_profile = profileManager.GetUserProfile(System.Web.HttpContext.Current.User.Identity.Name);&lt;br /&gt;&lt;br /&gt;     &lt;span style="color:green;"&gt;// Get the required profile property value from the profile&lt;br /&gt;     &lt;/span&gt;value = user_profile[&lt;span style="color: rgb(163, 21, 21);"&gt;"MyProperty"&lt;/span&gt;].Value.ToString();&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt; });&lt;br /&gt;}&lt;br /&gt;&lt;span style="color:blue;"&gt;catch &lt;/span&gt;(Exception e)&lt;br /&gt;{&lt;br /&gt; &lt;span style="color:blue;"&gt;return &lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;"Error getting user info: " &lt;/span&gt;+ e.Message.ToString();&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;user_profile["MyProperty"].Value gets or sets the profile property value.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;This is a very convenient way of using profile properties to store required information for each user. Properties can be set as read-only or not to appear in the user’s profile, which gives you even more control. &lt;/p&gt;System.Web.HttpContext.Current.User.Identity.Name returns the username (the login username) and it is used in the code example above to get the profile of the currently logged-in user.&lt;br /&gt;&lt;p&gt;&lt;b&gt;Tools You Never Knew You Had… (and what to do with them now that you’ve wised up!)&lt;/b&gt; &lt;/p&gt;With this simple solution to getting/setting a user’s profile property value, endless opportunities are now at hand. This small code snippet helps developers control, validate and use values stored for each user, without corrupting the database or resorting to other more complex and error-prone solutions.&lt;br /&gt;For those not needing to use an external application to get information from the users, a custom SharePoint web application can be developed and deployed on SharePoint. This way all the controls offered by ASP .NET or custom controls can be used to perform required operations on the data before it’s stored.&lt;br /&gt;&lt;p&gt;External applications running on the server can access this information the same way, so a bridge between SharePoint and applications like web sites, game servers, messaging apps, etc. can be easily created.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;SharePoint Complications, As Usual&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Watch out that the profile property might be set as read-only in SharePoint. Even if it’s the case however, the above code should still be able to access the profile because it’s running with elevated privileges. So if there is a situation in which the user is allowed to see the data but only modify it by using a service (like a web application or web service), this is a good way of doing it. &lt;/p&gt;Another gotcha is that the code above can only be used on the SharePoint server machine. This is due to the framework that SharePoint uses. To get information or to change data from a network on internet location, a SharePoint custom web service or web application can come in handy. Other ways of passing information will work too, like server-client applications, as long as the part running the above code is on the SharePoint server machine.&lt;br /&gt;&lt;p&gt;So we now have a way to store data and manipulate it according to our needs. We can control it, we can validate it and most important of all, we decide how the user interacts with the data. &lt;/p&gt;We’re now ready to start doing some serious SharePoint development!&lt;img src="http://feeds.feedburner.com/~r/macadamian/thefiles/~4/390669987" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/8080723372392435717/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=35928092&amp;postID=8080723372392435717" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/8080723372392435717" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/8080723372392435717" /><link rel="alternate" type="text/html" href="http://thefiles.macadamian.com/2008/09/bridge-sharepoint-user-profiles-and_12.html" title="Bridge SharePoint - User Profiles and User Profile Properties (part 2 of 2)" /><author><name>Romeo Dumitrescu</name><uri>http://www.blogger.com/profile/12048678127751485032</uri><email>noreply@blogger.com</email></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35928092.post-3480540278316123483</id><published>2008-09-10T11:51:00.000-04:00</published><updated>2008-09-10T13:07:05.673-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="web development" /><category scheme="http://www.blogger.com/atom/ns#" term="Authentication" /><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint" /><category scheme="http://www.blogger.com/atom/ns#" term="testing" /><title type="text">Bridge SharePoint - User Profiles and User Profile Properties (part 1 of 2)</title><content type="html">There is a constant need in SharePoint feature development to bridge SharePoint 2007 with other web applications. In order to create such a bridge, a variety of user information must be stored in the SharePoint database.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Warning: Do not tamper with the SharePoint database! No matter how tempting it is!&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;         Although this might sound as simple as a small SQL application, tampering with SharePoint’s database could lead to disastrous results and even complete and irreversible server crashes, since many of SharePoint’s recovery features rely on the database being intact. “Feeding” information to SharePoint through its database is unadvisable and sometimes very hard to do, mainly due to the complex structure of the database.&lt;br /&gt;&lt;br /&gt;         Fortunately there is a built-in solution to this problem that is both simple and efficient: &lt;span style="font-weight: bold;"&gt;User Profiles and User Profile Properties.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;         In this post we will see how SharePoint’s user profiles and profile properties can help us do our job fast and easy without worrying about crashing the server or breaking more features than we create.&lt;br /&gt;&lt;br /&gt;         Let’s start with the storing information problem.&lt;br /&gt;         Many developers have already considered using Profile Properties as way to store the required data, but have given up on using them due to their limitations (limited validation, control, variety). Controlling the user’s input and making sure that the values are correct is essential in any bridge, and often auto-generated values based on that data are necessary. SharePoint can only do so much, and this is usually the main reason why developers avoid using the custom profile properties.&lt;br /&gt;&lt;br /&gt;         &lt;span style="font-weight: bold;"&gt;Solution:  Manage information using the Microsoft.Office.Server.UserProfiles namespaces.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;         SharePoint Server 2007 stores user profiles in SQL Server, but the information can be imported from other data sources, such as:&lt;br /&gt;·    Active Directory&lt;br /&gt;·    Lightweight Directory Access Protocol directories (which is not Active Directory)&lt;br /&gt;·    Databases&lt;br /&gt;·    Enterprise applications (such as SAP or PeopleSoft) by defining a Business Data Catalog connection&lt;br /&gt;·    Web applications&lt;br /&gt;·    Custom SharePoint web services&lt;br /&gt;·    Standard .NET applications, etc.&lt;br /&gt;         The main classes are found in the Microsoft.Office.Server.UserProfiles namespaces. The assembly is Microsoft.Office.Server.dll found in C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\ISAPI.&lt;br /&gt;         The main objects to handle information within the User Profile store are:&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;UserProfile&lt;/span&gt;&lt;br /&gt;Allows you to access profile properties, the My Site, personalization links, and so on.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;UserProfileManager&lt;/span&gt;&lt;br /&gt;Gives access to a collection of UserProfile objects and allows you to create, edit, and retrieve user profile objects and properties from the user profile store.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;UserProfileConfigManager&lt;/span&gt;&lt;br /&gt;Manages the user profile configuration.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Note&lt;/span&gt;: In order to manage data in a custom user profile property, the property must be first created. You can use the following steps to create a profile property:&lt;br /&gt;&lt;br /&gt;1.    Start &gt; Administrative Tools &gt; SharePoint 3.0 Central Administrator&lt;br /&gt;2.    In the left panel, under Shared Services Administration, click SharedServices1&lt;br /&gt;3.    Click User Profiles and Properties&lt;br /&gt;4.    Under User Profile Properties, click Add Profile Property&lt;br /&gt;5.    Fill in the required data and click OK&lt;br /&gt;&lt;br /&gt;Now that we know that SharePoint accepts data from external sources and that it stores individual user values in user profile properties, it’s time to put the two together and find out how to store user data in profile properties from external data sources. This is the topic for part two of this post: Getting/Storing user data from external sources.&lt;img src="http://feeds.feedburner.com/~r/macadamian/thefiles/~4/388798542" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/3480540278316123483/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=35928092&amp;postID=3480540278316123483" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/3480540278316123483" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/3480540278316123483" /><link rel="alternate" type="text/html" href="http://thefiles.macadamian.com/2008/09/bridge-sharepoint-user-profiles-and.html" title="Bridge SharePoint - User Profiles and User Profile Properties (part 1 of 2)" /><author><name>Romeo Dumitrescu</name><uri>http://www.blogger.com/profile/12048678127751485032</uri><email>noreply@blogger.com</email></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35928092.post-2892693250199788712</id><published>2008-09-04T15:50:00.002-04:00</published><updated>2008-09-04T16:12:49.197-04:00</updated><title type="text">SharePoint says "Unknown Error"</title><content type="html">&lt;strong&gt;ERROR: Only Content controls are allowed directly in a content page that contains Content controls.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;By default, SharePoint doesn't seem willing to share some of its internal errors with developers opting instead to use a generic "Unknown Error" page.  The informative &lt;em&gt;(and I use the term loosely)&lt;/em&gt; error string above wasn't displayed in the browser until the file &lt;u&gt;C:\Inetpub\wwwroot\wss\VirtualDirectories\80\web.config&lt;/u&gt; was modified to disable custom error messages.&lt;br /&gt;&lt;br /&gt;By changing &lt;span style="color:#cc0000;"&gt;&amp;lt;SafeMode CallStack="false" ...&amp;gt;&lt;/span&gt; to &lt;span style="color:#cc0000;"&gt;&amp;lt;SafeMode CallStack="true" ...&amp;gt;&lt;/span&gt; and changing &lt;span style="color:#cc0000;"&gt;&amp;lt;customErrors mode="On" /&amp;gt;&lt;/span&gt; to &lt;span style="color:#cc0000;"&gt;&amp;lt;customErrors mode="Off" /&amp;gt;&lt;/span&gt;, the generic error page is replaced with a more detailed error message and maybe even a callstack.&lt;br /&gt;&lt;br /&gt;As for the error above?  It was caused by a comment that had been added to an .aspx file.  For some reasons, comments were not allowed because they didn't qualify as "content controls".&lt;img src="http://feeds.feedburner.com/~r/macadamian/thefiles/~4/383544390" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/2892693250199788712/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=35928092&amp;postID=2892693250199788712" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/2892693250199788712" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/2892693250199788712" /><link rel="alternate" type="text/html" href="http://thefiles.macadamian.com/2008/09/sharepoint-says-unknown-error.html" title="SharePoint says &quot;Unknown Error&quot;" /><author><name>Frederic LeBel</name><uri>http://www.blogger.com/profile/01870456065216884794</uri><email>noreply@blogger.com</email></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35928092.post-4171678228936563604</id><published>2008-08-03T19:33:00.000-04:00</published><updated>2008-08-03T19:33:01.375-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="web development" /><category scheme="http://www.blogger.com/atom/ns#" term="testing" /><title type="text">Performance reality check for web developers</title><content type="html">When I work on a web application, I usually have the luxury of running everything that I need locally on my developer machine. My browser, Web-server and database all working together without ever having to put a single packet on a real network.&lt;br /&gt;&lt;br /&gt;With today's web applications growing more complex and making use of asynchronous calls to the web server, this idealistic development environment makes it very difficult for the developer to assess the performance characteristics of the application. This can lead to surprises when the application is deployed to a real environment where users actually access it from remote locations.&lt;br /&gt;&lt;br /&gt;A good way to bring reality back to this equation is to make use of a proxy server. I like to use &lt;a href="http://donsproxy.sourceforge.net/"&gt;Don's Proxy&lt;/a&gt;. It is simple Java-based application that takes 1 minute to setup and lets you inject latency, errors and throttle your connection bandwidth. All of this is made in a manner that is independent of your browser or your web server. Most importantly. it does not require any changes to your application's code or setup.&lt;br /&gt;&lt;br /&gt;To use Don's Proxy, simply download the package, unzip and double-click the jar file. A simple GUI will open (&lt;a href="http://sourceforge.net/project/screenshots.php?group_id=211367"&gt;screenshot&lt;/a&gt;) that will prompt you for a port for the proxy to listen to and a host/port for the destination of your test web server. In the example screenshot, the test web server is running locally at port 8080 and the proxy is setup to listen on port 9090.&lt;br /&gt;&lt;br /&gt;Once the proxy is started, you just redirect your browser to the proxy's port and everything should work as before. The difference is that now, you can inject realistic network parameters like latency and bandwidth limitations. Don's Proxy also allows you to capture traffic as it goes through and perform other diagnostics without the use of a packet-sniffer.&lt;br /&gt;&lt;br /&gt;Hopefully, a more common use of tools like this will help curb developer enthusiasm for flashy Ajax behavior. Your users will thank you.&lt;img src="http://feeds.feedburner.com/~r/macadamian/thefiles/~4/354789557" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/4171678228936563604/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=35928092&amp;postID=4171678228936563604" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/4171678228936563604" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/4171678228936563604" /><link rel="alternate" type="text/html" href="http://thefiles.macadamian.com/2008/08/performance-reality-check-for-web.html" title="Performance reality check for web developers" /><author><name>Francis</name><uri>http://www.blogger.com/profile/11917210826902818268</uri><email>noreply@blogger.com</email></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35928092.post-7183137287562820116</id><published>2008-07-30T16:30:00.005-04:00</published><updated>2008-07-31T15:44:11.654-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="c++" /><category scheme="http://www.blogger.com/atom/ns#" term="embedded" /><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="cross-compiling" /><title type="text">Snake On A Phone</title><content type="html">&lt;p&gt;For a few years now, my main task at work has been working on the firmware of an IP phone. The phone runs VxWorks on a MIPS32 CPU; the firmware is written in C and C++.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;For slightly less time, I've been dabbling in python on my own time. Freedom from explicit typing was a refreshing change, and python's tendency to Just Work was a nice bonus.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;It was perhaps inevitable that I would one day try to combine phone and language. (why? because they were both there)&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;It wasn't obvious that the idea stood a chance. VxWorks is a bit off the OS beaten track, and might not provide all the functionality needed by Python's "core" (not with the same names, anyway). There might be some processor-specific pieces that would rule out MIPS32. And even if I could get something built, would it fit in the 2 or 3 MB of RAM (and even less flash) I could spare?&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;As it turns out, there was very little to worry about. Python's code is impressively (if perhaps unsurprisingly) portable, only needing a couple of tweaks to its build system and none at all to its source code. There doesn't seem to be anything CPU-dependant; and in the end, adding python to my firmware only cost me 1MB. It took me only a few evenings of tinkering to get a libpython built, linked into my firmware, and loaded on my phone, to the point that I could run this little experiment at the VxWorks shell:&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;br /&gt;  -&amp;gt; Py_Initialize()&lt;br /&gt;  value = 42 = 0x2a = '*'&lt;br /&gt;  -&amp;gt; PyRun_SimpleString("print 'Hello, World!'\n")&lt;br /&gt;  Hello, World!&lt;br /&gt;  value = 0 = 0x0&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;(the VxWorks shell being a peculiar animal that allows calling C functions by name, in this case giving me access to Python's C Extension API for a near-REPL experience)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;For my purposes, that's enough; I know it can work, and that's all I wanted. I don't expect to ever go further than this. But as little as it is, publishing how I got there might help someone get started on a real project; so here goes:&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;Porting python in 10 easy* steps&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;*for a suitable definition of easy&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;As far as embedding Python in an existing application (or firmware) is concerned, &lt;a href="http://docs.python.org/api/embedding.html"&gt;Python's own documentation&lt;/a&gt; should give you most of what you need&lt;br /&gt;&lt;/li&gt;&lt;p&gt;&lt;/p&gt;&lt;li&gt;You'll need a cross-compiling toolchain, i.e. a compiler that can be used on one platform (e.g. x86) and produces executables for use on a different platform (e.g. MIPS32). GCC is your best bet; it's what will make python's build system happiest, and there's lots of resources on getting a GCC cross-compiler working on the web, though it looks a bit daunting to me. I was fortunate in that, since I was already set up to build firmwares, I already had all the needed tools; I would guess that most people engaging on a similar project would be in the same position.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;p&gt;&lt;/p&gt;&lt;li&gt;In addition to the compiler (and assembler, linker, etc), you'll want to have a Unix-like environment to run Python's configure script and makefiles. If you're on Windows, cygwin will serve nicely.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;p&gt;&lt;/p&gt;&lt;li&gt;The 'configure' script needs some tweaking: it contains a few uses of AC_TRY_RUN, which will fail when cross-compiling.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;If you have a working 'autoconf', the simplest is to edit the 'configure.in' file. You can either remove the AC_TRY_RUN tests altogether or replace them by the newer, more cross-compiler-friendly &lt;a href="http://www.gnu.org/software/autoconf/manual/html_node/Runtime.html"&gt;AC_RUN_IFELSE&lt;/a&gt;. Then run 'autoconf' to regenerate the 'configure' script.&lt;br /&gt;&lt;/li&gt;&lt;li&gt; If you don't (as I didn't), you can brace yourself and go edit the 'configure' script directly. Running the script produces error messages that gives something to search for. The fix is actually simple: just remove the calls to 'exit' to allow the error to get ignored.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;p&gt;&lt;/p&gt;&lt;li&gt;The makefile also needs tweaking: just like 'configure', at some point it tries to compile and run a program. This appears to be in order to autogenerate some source files, which fortunately are already provided in the source distribution; so it's safe to disable this step. The simplest way:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;open "Makefile.pre.in"&lt;br /&gt;&lt;/li&gt;&lt;li&gt;find the place where "$(PGEN)" shows up AFTER a ':'&lt;br /&gt;&lt;/li&gt;&lt;li&gt;remove "$(PGEN)"&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;(this will only prevent the executable from getting built. The makefile will still attempt to run it, but it's written so that the resulting failure is ignored)&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;p&gt;&lt;/p&gt;&lt;li&gt;The configure script and makefile try to guess at the name of tools to use; you can give them a hint with environment variables. In my case I needed to set CC (the C Compiler) and AR (the "archiver", ie. what creates static libraries)&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;p&gt;&lt;/p&gt;&lt;li&gt;If you need to specify special command-line options to the compiler, environment variables can also be used. Annoyingly, 'configure' and the makefiles use different variable; you'll want to set CFLAGS and BASECFLAGS to the same thing.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;p&gt;&lt;/p&gt;&lt;li&gt;Finally you'll be ready to run the 'configure' script. You need to give it the special options &lt;a href="http://www.gnu.org/software/autoconf/manual/html_node/Specifying-Names.html"&gt;--build and --host&lt;/a&gt; to tell it you're cross-compiling, something like:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;$ ./configure --build=win32 --host=vxworks&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;(win32 and vxworks were a wild guess that happened to work for me. I got the impression the specific values didn't particularly matter)&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;p&gt;&lt;/p&gt;&lt;li&gt;You can then run 'make' to compile everything. If, like me, all you need is a static library, this will do it:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;$ make libpython2.5.a&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;p&gt;&lt;/p&gt;&lt;li&gt;There's a good chance some files under Modules/ will fail to compile (in my case, posixmodule.c). The file Module/Setup specifies (in a rather well-documented way) which Python modules (written in C) should be built into the python library; comment out the failing one, and re-run 'make'. I only had to disable posixmodule and pwdmodule; YMMV.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;And for me, that was it; nothing else needed manual intervention. If you run into more troubles (e.g. trying to build the actual python.exe), I'm afraid you're on your own.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;My next step was to figure out how to integrate the python library into my firmware; you'll have to figure out the corresponding steps for your own firmware/embedded application/whatever. Start with the &lt;a href="http://docs.python.org/api/embedding.html"&gt;'embedding' link&lt;/a&gt; for how to access python code from your code.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;If you want to be able to load python source files with 'import', pay particular attention to what that page says about PYTHONHOME; as for me, I put a putenv(PYHONHOME=/whatever") before the Py_Initialize call, letting me import /whatever/python2.5/*.py files (and possibly, though I haven't tried, .py files contained in a /whatever/python2.5/libpython2.5.zip)&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Happy cross-compiling!&lt;br /&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/macadamian/thefiles/~4/351854914" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/7183137287562820116/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=35928092&amp;postID=7183137287562820116" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/7183137287562820116" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/7183137287562820116" /><link rel="alternate" type="text/html" href="http://thefiles.macadamian.com/2008/07/snake-on-phone.html" title="Snake On A Phone" /><author><name>LPG</name><uri>http://www.blogger.com/profile/17088475660870758813</uri><email>noreply@blogger.com</email></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35928092.post-3825528010247369451</id><published>2008-07-24T07:00:00.001-04:00</published><updated>2008-07-25T14:31:21.824-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="outlook" /><category scheme="http://www.blogger.com/atom/ns#" term="oom" /><category scheme="http://www.blogger.com/atom/ns#" term="mapi" /><title type="text">Outlook Entry IDs Made Easy</title><content type="html">When developing for Outlook you will quickly realize that there's more than one way of doing things. For example, take a look at the number of APIs for interacting with Outlook:&lt;ul&gt;&lt;li&gt;Outlook Object Model (OOM)&lt;/li&gt;&lt;li&gt;MAPI&lt;/li&gt;&lt;li&gt;CDO&lt;/li&gt;&lt;li&gt;Office/Outlook COM Add-in (_IDTExtensibility2)&lt;/li&gt;&lt;li&gt;Exchange Client Extensions&lt;/li&gt;&lt;/ul&gt;That doesn't even include the six libraries included in the Outlook 2003 Integration API or the excellent 3rd-party &lt;a href="http://www.dimastr.com/redemption/"&gt;Redemption&lt;/a&gt; library. I'm positive there are others. Usually you won't use all these APIs in the same project. However, if you want to do anything significant in Outlook, you'll need to use the OOM and MAPI libraries.&lt;br /&gt;&lt;br /&gt;It's important to understand the relationship between MAPI and the OOM:&lt;ul&gt;&lt;li&gt;The MAPI API dates back to the early Outlook days. It's used for the messaging and storage subsystems in Outlook.&lt;/li&gt;&lt;li&gt;The Outlook Object Model sits on top of MAPI and wraps a minimal amount of its functionality. It also exposes some of the Outlook UI to the developer.&lt;/li&gt;&lt;/ul&gt;When you work with these APIs, you'll hit on the problem of linking them together. Outlook Entry IDs are a good example. Entry IDs uniquely identify most objects in the OOM and MAPI. Being very flexible, Entry IDs can take many shape or form and can cause headaches when you try to handle them.&lt;br /&gt;&lt;br /&gt;At its simplest, an Entry ID is a variable length byte buffer, sometimes represented with a simple byte array. In MAPI, most Entry IDs are represented by the ENTRYID structure:&lt;h3&gt;mapidefs.h&lt;/h3&gt;&lt;pre&gt;typedef struct { &lt;br /&gt;    BYTE abFlags[4]; &lt;br /&gt;    BYTE ab[MAPI_DIM]; &lt;br /&gt;} ENTRYID, FAR *LPENTRYID;&lt;/pre&gt;This structure usually comes wrapped in the SBinary structure.&lt;h3&gt;mapidefs.h&lt;/h3&gt;&lt;pre&gt;typedef struct _SBinary { &lt;br /&gt;    ULONG cb; &lt;br /&gt;    LPBYTE lpb; &lt;br /&gt;} SBinary, FAR *LPSBinary;&lt;/pre&gt;In the Outlook Object Model things take a turn for the worst:&lt;ul&gt;&lt;li&gt;Most times you see Entry IDs as a BSTR that is hex encoded (i.e. the strings look like this: "000F1329EC29A0382BC...").&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogs.msdn.com/stephen_griffin/archive/2007/07/03/you-mean-you-want-the-oom-to-actually-work.aspx"&gt;Sometimes&lt;/a&gt; it still uses a BSTR, but it doesn't encode the buffer, instead using the BSTR as a binary blob. Although inconsistent, this is &lt;a href="http://msdn.microsoft.com/en-us/library/ms221105(VS.85).aspx"&gt;perfectly valid&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;Sometimes it's useful to represent the Entry ID as a SAFEARRAY of VARIANT VT_UI1 (this is the format VB uses for its byte arrays). For example, I've needed to have a function that can return a property any type from a MAPI object that needs to be called through automation (i.e. VB). For example, the &lt;a href="http://www.dimastr.com/redemption/utils.htm"&gt;IMAPIUtils::HrGetOneProp&lt;/a&gt; method from the Redemption Library does this.&lt;/li&gt;&lt;/ul&gt;Is your head spinning? Mine was.&lt;br /&gt;&lt;br /&gt;I solved the problem by creating a class (yet another format!) to facilitate manipulation of all these formats:&lt;pre&gt;class EntryId&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt;    EntryId(EntryId const&amp; entryId);&lt;br /&gt;&lt;br /&gt;    // All explicit so that it's always clear what we are doing.&lt;br /&gt;    explicit EntryId(BSTR const* str, bool hexEncoded = true);&lt;br /&gt;    explicit EntryId(SBinary const* binary);&lt;br /&gt;    explicit EntryId(SAFEARRAY const* array);&lt;br /&gt;    explicit EntryId(unsigned long count, unsigned char const* bytes);&lt;br /&gt;&lt;br /&gt;    // Again, no implicit conversion&lt;br /&gt;    CComBSTR toString(bool hexEncoded = true) const;&lt;br /&gt;    CComSafeArray&lt;VARIANT&gt; toSafeArray() const;&lt;br /&gt;    std::vector&lt;unsigned char&gt; toByteArray() const;&lt;br /&gt;    // ... add more as you need them&lt;br /&gt;&lt;br /&gt;    // TODO: Add more custom helper functions.&lt;br /&gt;    bool isLongTermId() const;&lt;br /&gt;&lt;br /&gt;    // TODO: Add comparison operators for convenience and ordered &lt;br /&gt;    // container support (such as std::map keys). When comparing &lt;br /&gt;    // Entry Ids, remember you need to use the &lt;br /&gt;    // &lt;a href="http://msdn.microsoft.com/en-us/library/ms530706(EXCHG.10).aspx"&gt;IMAPISupport::CompareEntryIDs&lt;/a&gt; method.&lt;br /&gt;    &lt;br /&gt;private:&lt;br /&gt;    std::vector&amp;lt;unsigned char&amp;gt; m_buffer;&lt;br /&gt;}&lt;/pre&gt;Now whenever I get an Entry ID in any format, the first thing I do is convert it to an EntryId instance. This adds many convenient functionalities:&lt;ul&gt;&lt;li&gt;Standardized interface to all ids.&lt;/li&gt;&lt;li&gt;Easy comparison of entry ids.&lt;/li&gt;&lt;li&gt;EntryId is a copyable class and can be passed by value.&lt;/li&gt;&lt;li&gt;EntryId can be held in a STL container.&lt;/li&gt;&lt;li&gt;Your other helper classes and methods can use the EntryId as parameter instead of other formats.&lt;/li&gt;&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/macadamian/thefiles/~4/343897869" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/3825528010247369451/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=35928092&amp;postID=3825528010247369451" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/3825528010247369451" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/3825528010247369451" /><link rel="alternate" type="text/html" href="http://thefiles.macadamian.com/2008/07/outlook-entry-ids-made-easy.html" title="Outlook Entry IDs Made Easy" /><author><name>Jean-Yves Boudreau</name><uri>http://www.blogger.com/profile/15574049889457773118</uri><email>noreply@blogger.com</email></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35928092.post-8696210027750230726</id><published>2008-07-23T12:14:00.003-04:00</published><updated>2008-07-23T12:16:38.677-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="QA" /><category scheme="http://www.blogger.com/atom/ns#" term="software testing" /><category scheme="http://www.blogger.com/atom/ns#" term="testing" /><category scheme="http://www.blogger.com/atom/ns#" term="QC" /><title type="text">Software Testers - Don't Underestimate Their Worth for Success</title><content type="html">Sometimes, testing your application isn’t enough: sometimes your test cases need to be tested!   Testing doesn’t always give you what you’d expect.  In extreme cases, it can even give you a false sense of confidence in a product that is a complete failure.&lt;br /&gt;&lt;br /&gt;Recently, I was managing an offshore team developing a component for our client's core enterprise application.  We wrote extensive test cases and, because we were concerned about a lack of domain knowledge, we even had architects write some of the test cases.   Things were looking good as we approached the end of the development cycle: the product was behaving as it was supposed to; we were passing test cases; we were greenlighted by the QC ‘process’.&lt;br /&gt;&lt;br /&gt;Our confidence was high, and we were ready to move on to automated testing.  Then we found the problem.  It turns out that our test cases were written with a single user in mind.  The minute we started to use this component with concurrent user access, the system would pretty much lock up.  Our confidence evaporated.&lt;br /&gt;&lt;br /&gt;This was a big mistake.  Architects and technical leads both reviewed the test cases.  Nobody found the oversight at the time.   This was compounded by an ‘if it passes the test cases then it works’ mentality.&lt;br /&gt;&lt;br /&gt;Unfortunately, a solution to this problem isn’t as easy as ‘follow these three steps’.  But if we can take away a lesson learned from this, it is that testing the right way is not only very important to the success of a product, but it also shouldn’t be taken for granted.  If you haven’t noticed, QC/QA and testers were not included in the writing of test cases, thus bypassing all kinds of valuable experience that would most likely caught our newbie mistakes.&lt;br /&gt;&lt;br /&gt;Bottom line - Don’t underestimate the worth of your testers and their experience, it might just come back to bite you in the future.&lt;img src="http://feeds.feedburner.com/~r/macadamian/thefiles/~4/343704731" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/8696210027750230726/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=35928092&amp;postID=8696210027750230726" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/8696210027750230726" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/8696210027750230726" /><link rel="alternate" type="text/html" href="http://thefiles.macadamian.com/2008/07/software-testers-dont-underestimate.html" title="Software Testers - Don't Underestimate Their Worth for Success" /><author><name>Tony</name><uri>http://www.blogger.com/profile/17596211212687907094</uri><email>noreply@blogger.com</email></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35928092.post-7014789058428782665</id><published>2008-07-17T23:50:00.000-04:00</published><updated>2008-07-17T23:50:49.547-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="code quality" /><title type="text">Maintenance Nightmares: Commented out code</title><content type="html">I was working on an estimate for a prospective customer, and luckily I had the code to examine beforehand to see what it was doing.&lt;br /&gt;&lt;br /&gt;While examining the code, I noticed code like this:&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);"&gt;// Fix for bug 1021892&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);"&gt;// some code that was commented out.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;There were instances of this throughout the code.&lt;br /&gt;&lt;br /&gt;When I see this I instinctively cringe, I immediately think that there is no proper source control or defect tracking procedures (or tools) in place. While there may be the odd corner case where commented out code is acceptable, in general it is not and should be avoided.&lt;br /&gt;&lt;br /&gt;There are many better ways of dealing with this, the first way is to just delete the line of code, and when you commit/check-in the code, make sure you put a meaningful comment in the commit logs  that ties it to the defect it was changed for. You can often search the commit logs, and if you put the bug id in the commit log, you will get the change in your search.&lt;br /&gt;&lt;br /&gt;Another easy way to do this is to delete the line of code, make a patch, and when resolving the bug in your bug tracking software, attach the patch file to that issue. Then you can always see what you changed to fix the bug.&lt;br /&gt;&lt;br /&gt;Does anyone else having any suggestions for this?&lt;img src="http://feeds.feedburner.com/~r/macadamian/thefiles/~4/338650390" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/7014789058428782665/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=35928092&amp;postID=7014789058428782665" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/7014789058428782665" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/7014789058428782665" /><link rel="alternate" type="text/html" href="http://thefiles.macadamian.com/2008/07/maintenance-nightmares-commented-out.html" title="Maintenance Nightmares: Commented out code" /><author><name>Jason Mawdsley</name><uri>http://www.blogger.com/profile/12753716679505402680</uri><email>jason@macadamian.com</email></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35928092.post-1187988472518294639</id><published>2008-07-11T14:25:00.009-04:00</published><updated>2008-07-15T10:08:27.413-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="c++" /><category scheme="http://www.blogger.com/atom/ns#" term="optimization" /><category scheme="http://www.blogger.com/atom/ns#" term="compiler" /><title type="text">Alignment Matters</title><content type="html">When do these two snippets behave differently?&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;void* p = something();&lt;br /&gt;int i = *(int*)p;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;int i;&lt;br /&gt;void* p = something();&lt;br /&gt;memcpy(&amp;amp;i, p, sizeof(int));&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Answer: when 'something' returns a value that's not a multiple of "sizeof(int)".&lt;br /&gt;&lt;br /&gt;Some processor architectures only allow loading memory into N-byte registers from memory addresses that are a multiple of N (e.g. multiple of 4 for 32-bit registers). Using misaligned addresses can have some various interesting consequences, depending on the CPU; I've heard of at least these:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;It works fine&lt;/li&gt;&lt;li&gt;It works, but slowly (e.g. because the misalignment is detected and alternate instructions are used to load 1 byte at a time - I've heard that x86 works this way)&lt;/li&gt;&lt;li&gt;The program may crash due on an "invalid address" trap&lt;/li&gt;&lt;li&gt;The CPU may load data from the wrong address (e.g. if only multiples of 4 are valid addresses, the instruction might ignore the bottom 2 bits of the address)&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Last week, I got lucky: I discovered that the MIPS32 CPU on the phone I was programming falls in the "crash" category. (why lucky? because an "address load exception" message is much easier to debug than some corrupted data)&lt;br /&gt;&lt;br /&gt;Usually, we don't have to worry about such alignment issues; the compiler and runtime make sure that all objects it allocates go at addresses that have the right alignment for their type (e.g. malloc must return memory "suitably aligned" for all possible types).&lt;br /&gt;&lt;br /&gt;Trouble comes when we lie to the compiler, such as telling it by a cast that "p" points to an "int" when such is not the case. This is what happened to me: I was parsing a file, and the 4-byte-value-that-should-be-put-in-an-int followed an arbitrary-length string. It ended up on an odd address, and boom. (Here's another way I was lucky: it COULD have been a nice multiple of 4 in all my tests, only to come out odd on a client's desk)&lt;br /&gt;&lt;br /&gt;Functions like memcpy, of course, are required to work with all addresses (as expressed by taking void* parameters, which require no cast).&lt;br /&gt;&lt;br /&gt;Lesson of the day? Don't lie to your compiler!&lt;br /&gt;(alternate lesson: "casts: evil AND chaotic"?)&lt;img src="http://feeds.feedburner.com/~r/macadamian/thefiles/~4/336077839" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/1187988472518294639/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=35928092&amp;postID=1187988472518294639" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/1187988472518294639" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/1187988472518294639" /><link rel="alternate" type="text/html" href="http://thefiles.macadamian.com/2008/07/alignment-matters.html" title="Alignment Matters" /><author><name>LPG</name><uri>http://www.blogger.com/profile/17088475660870758813</uri><email>noreply@blogger.com</email></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35928092.post-6155040441432892493</id><published>2008-07-10T14:43:00.003-04:00</published><updated>2008-07-11T10:34:29.373-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="semantic" /><category scheme="http://www.blogger.com/atom/ns#" term="c#" /><title type="text">Compile Time Semantic Checking</title><content type="html">C# is a TypeSafe language, what about SemanticSafe?&lt;br /&gt;&lt;br /&gt;In a project I'm working on we have a lot of database records ids being passed around as integers.  Today I needed to add a new record id to this list.  Adding the new item to the function signature is easy. The hard part comes in making sure the right value is being assigned.&lt;br /&gt;&lt;pre&gt;Public void MyFunction(int TableA_ID, int TableB_ID, String someOtherValue);&lt;br /&gt;&lt;br /&gt;int A_ID = 5;&lt;br /&gt;int B_ID = 4;&lt;br /&gt;MyFunction(B_ID, A_ID, "Hello World");&lt;/pre&gt;&lt;br /&gt;So what happens when I compile? Nothing, it works fine. Yet that line where I called the function has just corrupted the entire database because those database ID's were transposed.  Which kinda sucks.&lt;br /&gt;&lt;br /&gt;It's one thing to guarantee type safety, what what about semantic safety?  An idea popped into my head to use the existing type-checking to accomplish this.&lt;br /&gt;&lt;pre&gt;    public struct UserID&lt;br /&gt; {&lt;br /&gt;     private int value;&lt;br /&gt;     public static implicit operator int(UserID source)&lt;br /&gt;     { return source.value; }&lt;br /&gt;&lt;br /&gt;     public UserID(int intValue)&lt;br /&gt;     {&lt;br /&gt;         value = intValue;&lt;br /&gt;     }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt; private void TryToFail(UserID test) { } &lt;br /&gt;&lt;br /&gt; UserId works = new UserId(5);&lt;br /&gt; int fails = works;&lt;br /&gt;&lt;br /&gt; TryToFail(works) //compiles fine&lt;br /&gt; TryToFail(fails) //Doesn't compile&lt;/pre&gt;&lt;br /&gt;Even though both works and fails contain the exact same value, the function can be made to fail if the values are put in the wrong order.  I used an implicit operator so that I didn't lose the convince of having a simple integer, neato.&lt;br /&gt;&lt;br /&gt;Obviously this technique is not something you would want to use for every possible field as there is one extra step involved in getting the value.  But if you only did this for the record IDs I think it would be enough gain to make it worthwhile.&lt;br /&gt;&lt;br /&gt;I would like to think of a way to do this so that it has compile time checking, but once compiled only contains the primitive value.   Any ideas?&lt;img src="http://feeds.feedburner.com/~r/macadamian/thefiles/~4/331968451" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/6155040441432892493/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=35928092&amp;postID=6155040441432892493" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/6155040441432892493" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/6155040441432892493" /><link rel="alternate" type="text/html" href="http://thefiles.macadamian.com/2008/07/compile-time-semantic-checking.html" title="Compile Time Semantic Checking" /><author><name>Jake</name><uri>http://www.blogger.com/profile/04529021825096290761</uri><email>noreply@blogger.com</email></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35928092.post-1109675262390353465</id><published>2008-07-09T11:31:00.009-04:00</published><updated>2008-07-10T13:51:15.376-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="IRM" /><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint" /><title type="text">Trouble Getting Your Custom Protector Called?</title><content type="html">You might be getting a lot of grey hair by developing your own custom protector for SharePoint.  Until recently, I was right there with you.  Having troubles getting your custom protector to be called by SharePoint?  I'm here to help.  I'm happy to tell you that it could be a simple fix.  A simple flag as a matter of fact.  If you haven't heard of the IrmAddInsEnabled flag, then this is what you must do.&lt;br /&gt;&lt;br /&gt;You need to set the IrmAddInsEnabled flag to true in the Central Admin page to get SharePoint to call any of the protector function calls (HrIsProtected, HrProtect, HrUnprotect).  This sets a Boolean value that specifies whether to enable Information Rights Management (IRM) addins.&lt;br /&gt;&lt;br /&gt;You can do this directly on the MOSS server from the 12 Hive (C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\BIN) by calling the following:&lt;br /&gt;&lt;br /&gt;On the MOSS server:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;'stsadm -o setproperty -propertyname irmaddinsenabled -propertyvalue "yes"'&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Alternatively, you can do this programmatically by using SharePoint via the IRM Settings by using SPIrmSettings.IrmAddins.  This can be done at the farm level or as granular as a per-list basis.&lt;br /&gt;&lt;br /&gt;IRM Settings for the FARM:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;SPWebService svc = SPFarm.Local.Services.GetValue&lt;spwebservice&gt;();&lt;br /&gt;SPIrmSettings irmSettings = svc.IrmSettings;&lt;br /&gt;&lt;br /&gt;//Specifies whether to enable Information Rights Management (IRM)&lt;br /&gt;//locally for sites&lt;br /&gt;irmSettings.IrmRMSEnabled = true; &lt;br /&gt;&lt;br /&gt;//Specifies whether to enable Information Rights Management (IRM)&lt;br /&gt;//addins&lt;br /&gt;irmSettings.IrmAddinsEnabled = true;&lt;br /&gt;&lt;br /&gt;//Sets the number of times the Information Rights Management (IRM)&lt;br /&gt;//settings have been changed&lt;br /&gt;irmSettings.IrmChanges += 2; &lt;br /&gt;&lt;br /&gt;svc.Update();&lt;br /&gt;&lt;/spwebservice&gt;&lt;/pre&gt;&lt;br /&gt;IRM Settings for the Individual Lists on FeatureActivated:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;SPWeb web = (SPWeb)properties.Feature.Parent; &lt;br /&gt;foreach (SPList list in web.Lists)&lt;br /&gt;{&lt;br /&gt;  // Specifies whether to enable Information Rights Management (IRM)&lt;br /&gt;  // for the list&lt;br /&gt;  list.IrmEnabled = true;&lt;br /&gt;&lt;br /&gt;  // Specifies whether to allow users to upload documents that do&lt;br /&gt;  // not support IRM &lt;br /&gt;  list.IrmReject = true;&lt;br /&gt; &lt;br /&gt;  list.Update();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;After you have done this, your custom protector should be called when the documents are checked in and out of your SharePoint system via the HrIsProtected, HrProtect, HrUnprotect methods.&lt;br /&gt;&lt;br /&gt;Goodluck!&lt;img src="http://feeds.feedburner.com/~r/macadamian/thefiles/~4/331842557" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/1109675262390353465/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=35928092&amp;postID=1109675262390353465" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/1109675262390353465" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/1109675262390353465" /><link rel="alternate" type="text/html" href="http://thefiles.macadamian.com/2008/07/trouble-getting-your-custom-protector.html" title="Trouble Getting Your Custom Protector Called?" /><author><name>Aaron Gensey</name><uri>http://www.blogger.com/profile/01484679392523969198</uri><email>noreply@blogger.com</email></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35928092.post-6869938301668289971</id><published>2008-07-07T11:38:00.009-04:00</published><updated>2008-07-08T11:36:47.069-04:00</updated><title type="text">Mining Project Scope with Python + SVN</title><content type="html">After developing a component for a fairly large enterprise application, I was tasked with coordinating a complete review of all code touched by our team.  As the project involved hundreds of commits across every tier of the application, this was not a trivial task.  I didn’t want to make developers hunt through SVN logs and JIRA - even if the result was accurate, producing meta-documentation in the time allotted for actual documentation seemed wasteful.  There had to be a way to automate it.  After failing to find an appropriate SVN tool via Google, I weighed the pros and cons [1] then decided that using an SVN API would be easy enough.&lt;br /&gt;&lt;br /&gt;&lt;strike&gt;To make it interesting&lt;/strike&gt; As part of my commitment to Macadamian’s core value of continual improvement, I decided to try out Python.  The following script was maybe an hour of entertaining work that saved at least a day of tedium.&lt;br /&gt;&lt;pre style="overflow: scroll; height: 50em;"&gt;&lt;br /&gt;import pysvn&lt;br /&gt;&lt;br /&gt;# Script variables.  Could be read from a command line or config. file.&lt;br /&gt;username = "jlennon"&lt;br /&gt;password = "yoko"&lt;br /&gt;projectFirstRevision = 103991&lt;br /&gt;svnRoot = "http://path/to/svn/trunk/"&lt;br /&gt;&lt;br /&gt;# Team members’ names for SVN commits.&lt;br /&gt;users = set([&lt;br /&gt;          "gharrison",&lt;br /&gt;          "rstarkey",&lt;br /&gt;          "jlennon",&lt;br /&gt;          "pmccartney",&lt;br /&gt;          "gmartin",&lt;br /&gt;          "pbest"&lt;br /&gt;          ])&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# Set up SVN callbacks.&lt;br /&gt;def get_login(realm, username, may_save):&lt;br /&gt;   return True, username, password, False;&lt;br /&gt;&lt;br /&gt;def get_log_message() :&lt;br /&gt;   return True, "log message called"&lt;br /&gt;&lt;br /&gt;client = pysvn.Client()&lt;br /&gt;client.callback_get_login = get_login&lt;br /&gt;client.callback_get_log_message = get_log_message&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# Convert the revision number into a pysvn revision.&lt;br /&gt;projectFirstRevision = pysvn.Revision(pysvn.opt_revision_kind.number, projectFirstRevision)&lt;br /&gt;&lt;br /&gt;# Get all commits since the project's first commit.&lt;br /&gt;items = client.log(&lt;br /&gt;           svnRoot,&lt;br /&gt;           pysvn.Revision(pysvn.opt_revision_kind.head),&lt;br /&gt;           projectFirstRevision,&lt;br /&gt;           discover_changed_paths=True,&lt;br /&gt;           )&lt;br /&gt;&lt;br /&gt;# Set up variables for storing commit information&lt;br /&gt;allPaths = set([])&lt;br /&gt;removedPaths = set([])&lt;br /&gt;&lt;br /&gt;# For each commit entry *made by one of this project's users*&lt;br /&gt;#   Add any deleted files in the commit to removedPaths&lt;br /&gt;#   Add any added/updated files to the list of all paths&lt;br /&gt;for item in [ e for e in items if e.author in users ]:&lt;br /&gt;&lt;br /&gt;   for changed_path in item.changed_paths:&lt;br /&gt;&lt;br /&gt;      if changed_path.action == "D":&lt;br /&gt;         removedPaths.add(changed_path.path)&lt;br /&gt;      else:&lt;br /&gt;         allPaths.add(changed_path.path)&lt;br /&gt;&lt;br /&gt;# Remove deleted files from allPaths, then display&lt;br /&gt;allPaths = allPaths - removedPaths&lt;br /&gt;&lt;br /&gt;for path in sorted(allPaths):&lt;br /&gt;   print path&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Overall, I was impressed by Python.  My biggest problem was with the structure of the documentation, but that’s to be expected with any new language.  My biggest surprise was that the indentation rules didn’t bother me – why is this cited as a show-stopper by so many developers?  I’ll definitely be coming back to Python to test its OO facilities.&lt;br /&gt;&lt;br /&gt;[1] The main con being that a developer would much rather write a neat SVN spider than write documentation.  In a leadership role, you have to think twice before eagerly firing up your compiler to solve a problem.&lt;img src="http://feeds.feedburner.com/~r/macadamian/thefiles/~4/329001884" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/6869938301668289971/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=35928092&amp;postID=6869938301668289971" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/6869938301668289971" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/6869938301668289971" /><link rel="alternate" type="text/html" href="http://thefiles.macadamian.com/2008/07/mining-project-scope-with-python-svn.html" title="Mining Project Scope with Python + SVN" /><author><name>Gord. P</name><uri>http://www.blogger.com/profile/10684846302006538110</uri><email>noreply@blogger.com</email></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35928092.post-698633490157004878</id><published>2008-07-02T11:25:00.000-04:00</published><updated>2008-07-02T11:28:45.853-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="RIL" /><category scheme="http://www.blogger.com/atom/ns#" term="Windows Mobile" /><title type="text">Getting RIL!!</title><content type="html">Have you ever wanted to mess around with calling functionality of a mobile phone running Windows Mobile?&lt;br /&gt;&lt;br /&gt;I have this nifty phone but how do I control it programmatically?&lt;br /&gt;&lt;br /&gt;Well, first of all, the Windows Mobile Radio Interface Layer works by having specific modules control the cellular component. Since we are in North America there are two different cellular protocol implementations: GSM and CDMA. Above this layer is an abstraction layer that hides the implementation of the underlying protocol so that applications/OEM phone developers can use the functionality of call handling (and other useful information) without getting down to how things work under the hood. So how do we, as an application, talk to this abstraction layer, which we'll just clump together and call it the RIL( Radio Interface Layer )? Good Question!&lt;br /&gt;&lt;br /&gt;Since cellular devices are really just modems that use AT commands, the RIL operates mainly from an asynchronous callback system. In fact most of the RIL functions really just map to AT commands. The application accessing the RIL makes a request to the RIL, and the RIL takes some time to process this request and sends back a result code indicating the success or failure of the request. In addition the RIL spits out notifications which our application can hook into and be informed of status changes related to the cellular network. So let's dig a little with some RIL examples.&lt;br /&gt;&lt;br /&gt;There are a few pitfalls by going down this path. Firstly you might run into situations where you're fighting for control with the resident dialer (the default phone application supplied to the mobile device; developed by Microsoft). There may also be some undocumented internal states that need to be obeyed or else it can lead to unintended behavior (i.e. device lock up).&lt;br /&gt;&lt;br /&gt;There are also some differences to note between CDMA and GSM RIL implementations. With GSM devices there can be multiple lines, and as such the RIL can fetch call information for each line. RIL can also manage the GSM lines to perform actions such as putting the call on hold or switching lines. In the CDMA environment, there is only one "real" line and one "virtual" line. That is, one line is used to represent two lines. Access between the two lines is achieved by sending a "flash" command. Call management is also not possible with CDMA. So when you call "RIL_GetCallList" for GSM, for example, you may be returned information for one or more lines depending on the call state. For CDMA, you will only see at most one line.&lt;br /&gt;&lt;br /&gt;You will have to get your hands on the ril.h and ril.lib files. Both of these files are floating around somewhere on the internet (try &lt;a href="http://www.xs4all.nl/%7Eitsme/projects/xda/ril.html"&gt;here&lt;/a&gt;). If you can get both of these files, link your application with ril.lib and away you go. If you can’t find ril.lib but have ril.h, you can dynamically link with the ril.dll file (contained in the “windows” folder on the device) since you know what some of the prototypes are.&lt;br /&gt;&lt;br /&gt;First we need to initialize our application with the RIL so that we can receive both results and notifications callbacks. Here’s some code to do this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;// keep this handle handy as we need it for further RIL commands&lt;br /&gt;HRIL rilHandle;&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;HRESULT hr = RIL_Initialize(&lt;br /&gt;   1,                  // index of the RIL port to use (e.g., 1 for RIL1:)&lt;br /&gt;   &amp;amp;resultCallBack,    // this is a pointer to your result call back method&lt;br /&gt;   &amp;amp;notifyCallback,    // this is a pointer to your notify call back method&lt;br /&gt;   RIL_NCLASS_ALL,     // all notification (except device specific)&lt;br /&gt;   (DWORD) this,       // custom param (could be a pointer to an instance of a class)&lt;br /&gt;   &amp;amp;rilHandle);        // returned handle to RIL instance&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;void CALLBACK resultCallback(&lt;br /&gt;   DWORD dwCode,&lt;br /&gt;   HRESULT hrCmdID,&lt;br /&gt;   const void *lpData,&lt;br /&gt;   DWORD cbData,&lt;br /&gt;   DWORD dwParam)&lt;br /&gt;&lt;br /&gt;{&lt;br /&gt;   // handle the results&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;void CALLBACK notifyCallback(&lt;br /&gt;   DWORD dwCode,&lt;br /&gt;   const void *lpData,&lt;br /&gt;   DWORD cbData,&lt;br /&gt;   DWORD dwParam)&lt;br /&gt;{&lt;br /&gt;   // handle the notification&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Note that we’ve initialize the RIL with a reference to our class as the user parameter which is passed to the result and notification callbacks. The parameter is optional; however having the class reference would be especially useful if you would like to perform further actions after receiving a result or notification.  More on this later.&lt;br /&gt;&lt;br /&gt;OK so what - I've just initialized myself with RIL - what can I do now?&lt;br /&gt;To answer that question, anything under the Sun related to call handling, and then some!!&lt;br /&gt;&lt;br /&gt;For example if you wish to check the call status of the phone you can do the following. First send a request for call list:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;HRESULT cmdID;&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;void getCallList()&lt;br /&gt;{&lt;br /&gt;   // call RIL_GetCallList with RIL handle from the initialization&lt;br /&gt;   cmdID = RIL_GetCallList(rilHandle);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Next we have to wait for the results:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;void CALLBACK resultCallback(&lt;br /&gt;   DWORD dwCode,&lt;br /&gt;   HRESULT hrCmdID,&lt;br /&gt;   const void *lpData,&lt;br /&gt;   DWORD cbData,&lt;br /&gt;   DWORD dwParam)&lt;br /&gt;{&lt;br /&gt;   If (cmdID == hrCmdID &amp;amp;&amp;amp; RIL_RESULT_OK == (dwCode &amp;amp; 0xff))&lt;br /&gt;   {&lt;br /&gt;       // lpData points to an array of &lt;t&gt; structures.&lt;br /&gt;       RILCALLINFO *lpCallInfo = (RILCALLINFO *)lpData;&lt;br /&gt;       // extract the call info from the structure and do something...&lt;br /&gt;...&lt;br /&gt;&lt;/t&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Notice how the cmdID return value of RIL_GetCallList matches hrCmdID in the callback. In a realistic scenario, multiple commands are sent and the results do not necessary return in the same order the commands were sent. As a result we would need to queue up the command IDs in order to properly identify the command represented by each callback&lt;br /&gt;&lt;br /&gt;Now what is notifiyCallback useful for? This function is called basically whenever an event occurs that is of a notification class that was registered during initialization (we registered with RIL_NCLASS_ALL in this case). For example, for an incoming call you would receive and handle the “ring” notification as follows:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;void CALLBACK notifyCallback(&lt;br /&gt;   DWORD dwCode,&lt;br /&gt;   const void *lpData,&lt;br /&gt;   DWORD cbData,&lt;br /&gt;   DWORD dwParam)&lt;br /&gt;{&lt;br /&gt;   if(dwCode &amp;amp; RIL_NCLASS_CALLCTRL)&lt;br /&gt;   {&lt;br /&gt;       switch(dwCode &amp;amp; (0xff | RIL_NCLASS_CALLCTRL))&lt;br /&gt;       {&lt;br /&gt;       case RIL_NOTIFY_RING:&lt;br /&gt;           // do something here&lt;br /&gt;...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Since the phone is ringing, it is probably best to get more information about the incoming call. If you remember from initialization we use the class reference as the custom parameter. This gives us the flexibility to send further RIL commands by either passing in the RIL handle (HRIL) or point to a function in the class. In this case we can point back to the getCallList function created earlier.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;MyClass* myClass = (MyClass*)dwParam;&lt;br /&gt;myClass-&gt;getCallList();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If we don’t have a function to point to, we can always send an RIL command on the fly by passing in the RIL handle from our class. For example to answer the call right away:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;MyClass* myClass = (MyClass*)dwParam;&lt;br /&gt;HRESULT hr = RIL_Answer(myClass-&gt;rilHandle);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;As a note, if we're not using the interface anymore we'll need to de-register ourselves:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;RIL_Deinitialize(rilHandle);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;To learn more about RIL and all its wonders, you should closely examine the ril.h header. There is some information on the &lt;a href="http://msdn.microsoft.com/en-us/library/aa920441.aspx"&gt;msdn site&lt;/a&gt; as well. The best way to learn about it, of course, is to just try it out yourself.&lt;br /&gt;&lt;br /&gt;(Originally written and concept by Quan Nguyen; modified and edited by Henry Yi)&lt;img src="http://feeds.feedburner.com/~r/macadamian/thefiles/~4/324985007" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/698633490157004878/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=35928092&amp;postID=698633490157004878" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/698633490157004878" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/698633490157004878" /><link rel="alternate" type="text/html" href="http://thefiles.macadamian.com/2008/07/getting-ril.html" title="Getting RIL!!" /><author><name>Henry Yi</name><uri>http://www.blogger.com/profile/13165444059632676825</uri><email>noreply@blogger.com</email></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35928092.post-7005907291298653959</id><published>2008-06-27T18:52:00.004-04:00</published><updated>2008-06-27T19:02:20.847-04:00</updated><title type="text">Pure CSS Image Rollover without background-image</title><content type="html">The other day I was in a situation where I had an image that changed to another image when the user mouses over it. Usually I will do this in one of two very standard ways:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The typical javascript approach: using the onMouseOver and onMouseOut events to swap the images.&lt;/li&gt;&lt;li&gt;The typical css approach: an element that sets its background-image attribute to the default image, and changes its background-image attribute to the rollover image when the :hover pseudoclass is activated.&lt;/li&gt;&lt;/ul&gt;Unfortunately, neither of these solutions were optimal as I was looking for a pure-CSS solution (so no javascript) and needed the image to have its own &amp;lt;img&amp;gt; tag (so no background-image). After playing around with my selectors a little, I came up with this little gem:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;u&gt;The HTML&lt;/u&gt;:&lt;br /&gt;&lt;pre&gt;&amp;lt;div class="buttonContainer"&amp;gt;&lt;br /&gt; &amp;lt;img class="rest" src="link_rest.png" /&amp;gt;&lt;br /&gt; &amp;lt;img class="roll" src="link_roll.png" /&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;u&gt;The CSS&lt;/u&gt;:&lt;br /&gt;&lt;pre&gt;div.buttonContainer img.roll {&lt;br /&gt; display: none;&lt;br /&gt;}&lt;br /&gt;div.buttonContainer:hover img.roll {&lt;br /&gt; display: inline;&lt;br /&gt;}&lt;br /&gt;div.buttonContainer:hover img.rest {&lt;br /&gt; display: none;&lt;br /&gt;}&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;This neat CSS trick leaves the images in the html and changes the image on rollover with minimal mark-up. It works by abstracting the :hover pseudoClass to the container, loading both images into the page, and controlling the rollover effect using the images' display attribute.&lt;br /&gt;&lt;br /&gt;One word of caution: some older browsers (I'm looking at you, IE6) have poor support for the :hover pseudoclass, which renders this example ineffective; thus if you're supporting a lot of legacy browsers, this may not be for you. However, if you need a rollover that uses actual image tags and want to avoid using javascript, this may be just what you need.&lt;img src="http://feeds.feedburner.com/~r/macadamian/thefiles/~4/321650268" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/7005907291298653959/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=35928092&amp;postID=7005907291298653959" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/7005907291298653959" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/7005907291298653959" /><link rel="alternate" type="text/html" href="http://thefiles.macadamian.com/2008/06/pure-css-image-rollover-without.html" title="Pure CSS Image Rollover without background-image" /><author><name>Dan Menard</name><uri>http://www.blogger.com/profile/07261008052647160453</uri><email>noreply@blogger.com</email></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35928092.post-202477328236774508</id><published>2008-06-17T17:19:00.021-04:00</published><updated>2008-06-25T16:41:19.077-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Windows Mobile" /><title type="text">Obtaining the voicemail number on Windows Mobile phones</title><content type="html">The voicemail number, if available, may be stored in various locations on the Windows Mobile phone device depending on the type and carrier. In most cases, the number will show up somewhere in the registry. From experience I have found them in one of several locations under HKEY_CURRENT_USER:&lt;br /&gt;&lt;br /&gt;\Software\Microsoft\Vmail\PhoneNumber1&lt;br /&gt;\Software\Microsoft\Vmail\PhoneNumber2&lt;br /&gt;\Software\Microsoft\Vmail\UserProvidedNumber1&lt;br /&gt;\Software\Microsoft\Vmail\CarrierProviderNumber1&lt;br /&gt;\System\State\Messages\vmail\VMailNumber&lt;br /&gt;\Palm\State\Messages\vmail\VMailNumber&lt;br /&gt;&lt;br /&gt;On some GSM devices however the number isn’t always updated properly in the registry. In that case you would have to fetch it direct from the SIM card. In fact it is probably safest to fetch it from the SIM card first since this ensures a more accurate number.&lt;br /&gt;&lt;br /&gt;If you do some internet searches and dig through some of the &lt;a href="http://www.3gpp.org/specs/specs.htm"&gt;3GPP specifications for (U)SIM&lt;/a&gt; (i.e. 3GPP TS 31.102, 51.011) you will find that the voicemail number is stored in the EF&lt;sub&gt;MBDN&lt;/sub&gt; (Mailbox Dialing Numbers) file located at either 6FC7 for 3G devices or 6F17 for 2G.&lt;br /&gt;&lt;br /&gt;We can get the voicemail file from the SIM using the &lt;a href="http://msdn.microsoft.com/en-us/library/aa454262.aspx"&gt;SIM Manager API&lt;/a&gt;. Note that some of these are &lt;a href="http://msdn.microsoft.com/en-us/library/aa919335.aspx"&gt;privileged functions&lt;/a&gt;. You also have to make sure to add “cellcore.lib” as a dependency to your project. The code would look as follows:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;// include the SIM Manager API&lt;br /&gt;#include &lt;simmgr.h&gt;&lt;br /&gt;&lt;br /&gt;// set the voicemail addresses&lt;br /&gt;#define EF_MBDN_2G 0x6F17&lt;br /&gt;#define EF_MBDN_3G 0x6FC7&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;std::string getVoicemailNumber()&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;std::string number;&lt;br /&gt;HSIM hSim = 0;&lt;br /&gt;HRESULT hr = S_OK;&lt;br /&gt;&lt;br /&gt;// initialize&lt;br /&gt;hr = SimInitialize (0, 0, 0, (LPHSIM)&amp;hSim);&lt;br /&gt;&lt;br /&gt;if (S_OK == hr)&lt;br /&gt;{&lt;br /&gt;    DWORD address = EF_MBDN_2G;&lt;br /&gt;    SIMRECORDINFO simRecordInfo = {0};&lt;br /&gt;    simRecordInfo.cbSize = sizeof(SIMRECORDINFO);&lt;br /&gt;&lt;br /&gt;    // check the 2G address for the file&lt;br /&gt;    hr = SimGetRecordInfo(hSim, address, &amp;simRecordInfo);&lt;br /&gt;&lt;br /&gt;    // The file may hold more than one number for devices with&lt;br /&gt;    // multiple lines; however we will assume only one line.&lt;br /&gt;    // A valid file needs to be "linear" type and at least 14 bytes.&lt;br /&gt;    if ( S_OK != hr ||&lt;br /&gt;         SIM_RECORDTYPE_LINEAR != simRecordInfo.dwRecordType ||&lt;br /&gt;         simRecordInfo.dwItemCount == 0 ||&lt;br /&gt;         simRecordInfo.dwSize &lt; 14 )&lt;br /&gt;    {&lt;br /&gt;        // no valid 2G file, check the 3G address&lt;br /&gt;        address = EF_MBDN_3G;&lt;br /&gt;        memset(&amp;simRecordInfo, 0, sizeof(simRecordInfo));&lt;br /&gt;        simRecordInfo.cbSize = sizeof(SIMRECORDINFO);&lt;br /&gt;        hr = SimGetRecordInfo(hSim, address, &amp;simRecordInfo);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    if ( S_OK == hr &amp;&amp;&lt;br /&gt;         SIM_RECORDTYPE_LINEAR == simRecordInfo.dwRecordType &amp;&amp;&lt;br /&gt;         simRecordInfo.dwItemCount &gt; 0 &amp;&amp;&lt;br /&gt;         simRecordInfo.dwSize &gt;= 14)&lt;br /&gt;    {&lt;br /&gt;        // allocate the specified size&lt;br /&gt;        LPBYTE buf = (LPBYTE)LocalAlloc(LPTR, simRecordInfo.dwSize);&lt;br /&gt;        DWORD bytesRead = 0;&lt;br /&gt;        &lt;br /&gt;        // read the SIM file&lt;br /&gt;        hr = SimReadRecord(hSim, address, SIM_RECORDTYPE_LINEAR, 1,&lt;br /&gt;                buf, simRecordInfo.dwSize, &amp;bytesRead);&lt;br /&gt;&lt;br /&gt;        if (S_OK ==  hr &amp;&amp; bytesRead &gt;= 14)&lt;br /&gt;        {&lt;br /&gt;            // handle the bytes received&lt;br /&gt;...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now that we have the file, we need to interpret the bytes into a useful number. The 3GPP specifications show the EF&lt;sub&gt;MBDN&lt;/sub&gt; structure as follows:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Bytes        Description                                 M/O  Length&lt;br /&gt;----------------------------------------------------------------------&lt;br /&gt;1 to X       Alpha Identifier                             O   X bytes&lt;br /&gt;X+1          Length of BCD number/SSC contents            M   1 byte&lt;br /&gt;X+2          TON and NPI                                  M   1 byte&lt;br /&gt;X+3 to X+12  Dialling Number/SSC contents                 M   10 bytes&lt;br /&gt;X+13         Capability/Configuration2 Record Identifier  M   1 byte&lt;br /&gt;X+14         Extension 6 Record Identifier                M   1 byte&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The first few bytes (1 to X) are the optional identifier. In most cases it will just show the words “voicemail”.  The last 14 bytes describe the voicemail number with up to 10 bytes representing the number as binary coded decimals. For our purpose we can ignore Capability/Configuration2 Record Identifier and Extension 6 Record Identifier. The way to interpret the bytes is described in the 3GPP specifications 31.102 clause 4.4.2.3 for EF&lt;sub&gt;ADN&lt;/sub&gt; (Abbreviated dialing numbers). We can proceed to get the number from the bytes as follows:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;        // use the last 14 bytes&lt;br /&gt;        char data[14];&lt;br /&gt;        memcpy(&amp;data, &amp;buf[bytesRead-14], 14);&lt;br /&gt;&lt;br /&gt;        // byte 0 (X+1) is the length of dialing number&lt;br /&gt;        int length = data[0];&lt;br /&gt;&lt;br /&gt;        std::stringstream ss;&lt;br /&gt;&lt;br /&gt;        // TON and NPI determines the type of number&lt;br /&gt;        // see 3GPP specifications 31.102 clause 4.4.2.3&lt;br /&gt;        if (0x90 == (0xF0 &amp; data[1]))&lt;br /&gt;        {&lt;br /&gt;            // add the + for international numbers&lt;br /&gt;            ss &lt;&lt; '+';&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        // convert the BCD bytes to Ascii chars&lt;br /&gt;        for (int idx=2; idx &lt; length+1; idx++)&lt;br /&gt;        {&lt;br /&gt;            // break the byte into 2 nibbles&lt;br /&gt;            BYTE nibble[2];&lt;br /&gt;            nibble[0] = data[idx] &amp; 0xF;&lt;br /&gt;            nibble[1] = (data[idx] &gt;&gt; 4) &amp; 0xF;&lt;br /&gt;&lt;br /&gt;            for (int i=0; i&lt;2; i++)&lt;br /&gt;            {&lt;br /&gt;                if (nibble[i] == 0xA)&lt;br /&gt;                {&lt;br /&gt;                    // 0xA represents a *&lt;br /&gt;                    ss &lt;&lt; '*';&lt;br /&gt;                }&lt;br /&gt;                else if (nibble[i] == 0xB)&lt;br /&gt;                {&lt;br /&gt;                    // 0xB represents a #&lt;br /&gt;                    ss &lt;&lt; '#';&lt;br /&gt;                }&lt;br /&gt;                else if (nibble[i] &lt; 0xA)&lt;br /&gt;                {&lt;br /&gt;                    // add the number&lt;br /&gt;                    ss &lt;&lt; (char) ('0' + nibble[i]);&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        // set the voicemail number&lt;br /&gt;        ss &gt;&gt; number;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now that we have the voicemail number we should free the buffer and sim handle and return the number:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;        // free the buffer&lt;br /&gt;        LocalFree( buf );&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // deinitialize&lt;br /&gt;    SimDeinitialize( hSim );&lt;br /&gt;}&lt;br /&gt;return number;&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;There are a couple of things to note. Here I’ve handled both the 2G and 3G cases, however it is probably better to detect which type is being used beforehand. Also note that I have assumed the case of only one voicemail number. For a multi-line scenario you would have to check if there are more than one number stored in the SIM file. For a more detailed look on how the numbers are stored please refer to the 3GPP specifications.&lt;img src="http://feeds.feedburner.com/~r/macadamian/thefiles/~4/314130505" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/202477328236774508/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=35928092&amp;postID=202477328236774508" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/202477328236774508" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/202477328236774508" /><link rel="alternate" type="text/html" href="http://thefiles.macadamian.com/2008/06/obtaining-voicemail-number-on-windows.html" title="Obtaining the voicemail number on Windows Mobile phones" /><author><name>Henry Yi</name><uri>http://www.blogger.com/profile/13165444059632676825</uri><email>noreply@blogger.com</email></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35928092.post-7877721394936932293</id><published>2008-06-09T13:15:00.015-04:00</published><updated>2008-06-17T18:54:03.293-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Windows Mobile" /><title type="text">Detecting the phone buttons on WM5/6</title><content type="html">When working on a project that involved creating a custom dialer for Windows Mobile devices, one of the more important tasks is enabling the detection of the Send (green, off-hook) and Hang-up (red, on-hook) button presses at all times.  The difficulty with this feat is that the Windows Mobile OS has specific needs for these buttons so you have to be careful with how you go about using them.&lt;br /&gt;&lt;br /&gt;For example the Send button is used for launching the phone application (cprog.exe by default), and also perform phone related tasks like making and answering calls or calling a contact. The Hang-up button is used to minimize dialogs and hang up active calls.&lt;br /&gt;&lt;br /&gt;On some devices the Hang-up button can have other behaviors such as acting as a power button or enabling keyboard lock.  It’s important to know these facts, because depending on what you intend to do with the Send or Hang-up buttons, you may cause existing features of the OS to not function.&lt;br /&gt;&lt;br /&gt;There are several methods to detect the Send and Hang-up buttons, but only a few methods will let you safely co-exist with the existing features of the Windows Mobile OS. I’ll first talk about obtaining the key presses through use of keyboard hook (SetWindowsHook) and why you shouldn’t use it. This is the first method I used for the project but quickly learned about the various limitations. If you do an Internet search for “Windows Mobile SetWindowsHook” you will obtain several pages explaining how to use SetWindowsHook on the device to detect each key press.  Using this method to detect the Send or Hang-up keys you may discover several set backs.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;You are not just intercepting the Send or Hang-up keys but every key press so you’ll have to be extra careful about handling them.&lt;/li&gt;&lt;li&gt;If an existing application already has the keyboard hook, you may not be able to use it. On a device like the Palm Treo 700/750 you may find that the Key-guard feature no longer works. This is because the Palm Key-guard also relies on the keyboard hook and can no longer use it if another application has control of it.&lt;/li&gt;&lt;li&gt;You may find that certain features that rely on Send/Hang-up no long work. For example you can no longer dial a number from Contacts with the Send button.&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;There are ways around these limitations of course, but it would require a lot of manual handling from your application.&lt;br /&gt;&lt;br /&gt;Another method of key detection is the use of hotkey registration. Microsoft provides us with the “RegisterHotKey” function which essentially allows you to register any button with your application window as a hotkey using the virtual key codes (VK_TTALK for Send, VK_TEND for Hang-up).  What this does is, when the registered key is pressed; it will send you a WM_HOTKEY message, even if your window is not in the foreground, allowing you to handle it.&lt;br /&gt;&lt;br /&gt;However there are a couple limitations when dealing with the Send and Hang-up keys. You may find that attempting to register either buttons as a hot key will fail. The reason is that the TaskBar (PPC) or Tray (Smartphone) already has Send button registered as a hotkey and the phone application has the Hang-up button.&lt;br /&gt;&lt;br /&gt;You can forcibly “steal” the hot key using either the “UnregisterHotKey” function or the hidden “UnregisterFunc1” function; however taking the hot key away from their respective owners would render some features useless as with the cases when using “SetWindowsHook”.&lt;br /&gt;&lt;br /&gt;After some experimentation I have found that there is a unique way in which you may register the Send and Hang-up buttons (and possibly other buttons) as hot keys. I’ve discovered that it is possible to register a button using 0x2001 as a modifier (some others will work as well such 0x2002, etc). What this does is it will generate a WM_HOTKEY message for you when pressing the Send button without interfering with the existing hot key registration held by the TaskBar or Tray or phone application. The limitation here, however, is that you will only get “one shot”; that is, only one WM_HOTKEY is generated and successive key presses will have no notifications. The solution is simply to register the key again. The code would look as follows (note that error and results checking are left out for simplicity)&lt;br /&gt;&lt;br /&gt;&lt;pre class="code-java"&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;// setup the window to receive the hot key message&lt;br /&gt;ON_MESSAGE(WM_HOTKEY, &amp;amp;MyappDlg::OnHotkey)&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;// define some of the values to use for registering hot keys&lt;br /&gt;#define ONE_SHOT_MOD        0x2001&lt;br /&gt;#define VK_TTALK_ID         0x07&lt;br /&gt;#define VK_TEND_ID          0x08&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;// register the Send and Hang-up buttons with the unique modifier&lt;br /&gt;::RegisterHotKey(m_hWnd, VK_TTALK_ID, ONE_SHOT_MOD, VK_TTALK);&lt;br /&gt;::RegisterHotKey(m_hWnd, VK_TEND_ID, ONE_SHOT_MOD, VK_TEND);&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;// wait for and handle the hot key messages&lt;br /&gt;afx_msg LRESULT MyappDlg::OnHotkey( WPARAM wParam, LPARAM lParam )&lt;br /&gt;{&lt;br /&gt;switch (lParam &gt;&gt; 16)&lt;br /&gt;{&lt;br /&gt;case VK_TTALK:&lt;br /&gt;// reregister VK_TTALK to get the next key press&lt;br /&gt;::RegisterHotKey(m_hWnd, VK_TTALK_ID, ONE_SHOT_MOD, VK_TTALK);&lt;br /&gt;// handle the keypress...&lt;br /&gt;break;&lt;br /&gt;case VK_TEND:&lt;br /&gt;// reregister VK_TEND to get the next key press&lt;br /&gt;::RegisterHotKey(m_hWnd, VK_TEND_ID, ONE_SHOT_MOD, VK_TEND);&lt;br /&gt;// handle the keypress...&lt;br /&gt;break;&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;&lt;/span&gt; &lt;/pre&gt;So there you have it. Each time the Send and Hang-up buttons are pressed you get a notification and you don’t have to worry about interfering with the normal operations of each button.&lt;img src="http://feeds.feedburner.com/~r/macadamian/thefiles/~4/308197413" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/7877721394936932293/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=35928092&amp;postID=7877721394936932293" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/7877721394936932293" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/7877721394936932293" /><link rel="alternate" type="text/html" href="http://thefiles.macadamian.com/2008/06/detecting-phone-buttons-on-wm56.html" title="Detecting the phone buttons on WM5/6" /><author><name>Henry Yi</name><uri>http://www.blogger.com/profile/13165444059632676825</uri><email>noreply@blogger.com</email></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35928092.post-7890267075123550411</id><published>2008-05-23T12:36:00.005-04:00</published><updated>2008-05-23T12:48:42.722-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Barcamp" /><category scheme="http://www.blogger.com/atom/ns#" term="Netbooks" /><category scheme="http://www.blogger.com/atom/ns#" term="UMPC" /><title type="text">UMPCs And The Race To The Bottom - Or how much more does a Flash SSD weights, when it's full with data?</title><content type="html">Our last Macadamian Barcamp session focused on &lt;a href="http://www.umpcportal.com/"&gt;Ultra Mobiles and Netbook PCs&lt;/a&gt;. The whole race to the bottom seem to have started when the One Laptop Per Child project took the initiative of creating an affordable ultra-mobile PC aimed at developing countries school children. &lt;a href="http://toni.schneidersf.com/2007/12/26/olpc-versus-eeepc/"&gt;Asus followed shortly&lt;/a&gt; and its Eee PC grabbed most of our attention with its slim size and crispy screen.&lt;br /&gt;&lt;br /&gt;On top of portability, we found that most UMPCs offer the following advantages:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Bigger screens compared to smartphones, Wi-Fi and now &lt;a href="http://en.wikipedia.org/wiki/WiMAX"&gt;WiMAX&lt;/a&gt; support (some Phillips devices already support WiMAX, and Nokia tablets will have WiMAX this summer).&lt;/li&gt;&lt;li&gt;Most can be used as a car GPS, most have GPS built-in, others can use a Bluetooth or USB GPS receiver.&lt;/li&gt;&lt;li&gt;They're good for note taking, Web browsing, email writing - They're great for common tasks and while most don't handle Vista very well, they have enough horsepower to run most applications written for desktop PCs.&lt;/li&gt;&lt;/ul&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://thefiles.macadamian.com/uploaded_images/EeePC_OMPC_barcamp-773632.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://thefiles.macadamian.com/uploaded_images/EeePC_OMPC_barcamp-773617.jpg" alt="" border="0" /&gt;&lt;/a&gt;There's always the power versus battery life aspect, which is generally slim compared to smartphones. The One Laptop Per Child PC battery lasts longer but its intentional Fisher-Price looks and ruggedness make it only valuable for either elementary-aged children or front line military soldiers.&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://www.ultramobilegeek.com/2007/11/asus-eee-701-vs-nokia-n810-linux-fight.html"&gt;Nokia Internet Tablets&lt;/a&gt; looks very promising since they seem to have a good balance between battery life, available applications and horsepower.&lt;br /&gt;&lt;br /&gt;Now that most computer vendors have embraced the idea of making Asus Eee-like PCs, we can only expect UMPCs will follow the same fast-paced evolution as cellphones and competition should keep their costs low. Both Eee PC and OLPC can now run WindowsXP. This doesn't make them gain an extra gram, they might even cost cheaper but personally, I feel using them without their native OSes just ain't Kosher.&lt;img src="http://feeds.feedburner.com/~r/macadamian/thefiles/~4/296703612" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/7890267075123550411/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=35928092&amp;postID=7890267075123550411" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/7890267075123550411" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/7890267075123550411" /><link rel="alternate" type="text/html" href="http://thefiles.macadamian.com/2008/05/umpcs-and-race-to-bottom-or-how-much.html" title="UMPCs And The Race To The Bottom - Or how much more does a Flash SSD weights, when it's full with data?" /><author><name>Jean-Claude Batista</name><uri>http://www.blogger.com/profile/03332245115965740988</uri><email>noreply@blogger.com</email></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35928092.post-6946662272951619842</id><published>2008-05-22T09:35:00.005-04:00</published><updated>2008-05-22T10:48:52.581-04:00</updated><title type="text">Software Metrics : What are they, and what can they do for you</title><content type="html">&lt;span style="font-size:130%;"&gt;What are software metrics?  &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This might be a term you have heard before. Simply put, they are a way to quantify aspects of source code.&lt;br /&gt;&lt;br /&gt;These aspects vary, and each have a different significance. ... it will make more sense if you see some examples:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Source_lines_of_code"&gt;&lt;span style="font-weight: bold;"&gt;LOC&lt;/span&gt; - Lines of code&lt;/a&gt;.   This metric is simply the line count per file, per project, per function, per class, etc.  Its value is that you can determine when code is growing beyond control.  The refactoring remedy is to split up the file/class/method into smaller, more manageable parts.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;NSM &lt;/span&gt;- Number of static methods/fields.  Excessive use of the static modifier is an indication that something is amiss.  The refactoring remedy may include using a Singleton design pattern, or reworking the class design.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;LCC &lt;/span&gt;- Lines of comments.  This is the total number of lines of comments.  When taken in ratio with the lines of code, you get a vague idea of how well documented your code base is.  It is a fairly common practice to generate API documentation from source, so this metric can be especially valuable if the project is a library.&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Cyclomatic_complexity"&gt;&lt;span style="font-weight: bold;"&gt;VG&lt;/span&gt; -Cyclomatic Complexity&lt;/a&gt;.  This metric is not as complex as the name sounds.  It is simply the count of the possible linearly independent paths the code may take.  Every IF, FOR, WHILE, DO,  CASE and trinary operator increments the count.  This can help identify poorly written code (ie huge if-else statements),  as well as potential slow spots.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;LCOM &lt;/span&gt;- Lack of Cohesion of Methods.  LCOM is a formula for detecting the &lt;a href="http://en.wikipedia.org/wiki/Cohesion_%28computer_science%29"&gt;cohesiveness &lt;/a&gt;of a class.  It can indicate when it may be time to split a class into two or more specialized classes.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;DIT &lt;/span&gt;- Depth of inheritance tree.  This metric is the number of levels a class is sub-classed.  On its own, the value doesn't necessarily indicate a need for refactoring, unless the base class wasn't designed for such a task.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;NORM &lt;/span&gt;- Number of overridden methods.  NORM can be useful for detecting classes that have evolved beyond their original design.  It might indicate better abstraction is needed at a low level.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;NOM &lt;/span&gt;- Number of methods.  The number of methods can be useful for detecting when a class has become over grown.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;This is only a partial list of some software metrics that can identify weak spots in your code base.  It is also certainly possible to dream up software metrics of your own, such as the number of preprocessor "#if" statements used.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;How to harness software metrics&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;All these numbers are quite meaningless without context.  What is needed are tools.  An ideal tool should run the software metric calculator on every file that is checked into a software repository.  The metrics could then be stored and compared per file, and an action could be taken when a particular metric threshold has been crossed.  From that trigger an appropriate action could be applied, such as sending out an email to the project manager, or creating a &lt;a href="http://www.atlassian.com/software/jira/"&gt;JIRA&lt;/a&gt; task to refactor the file.   By using the type of metric, a list of possible refactoring remedies could be supplied to steer the developer on the right track.&lt;br /&gt;&lt;br /&gt;Another desirable feature would be instant red/yellow/green status on projects and individual files, and trend when refactoring will be needed as metric counts increase.  This would be the real power of such a system, being able to see instantly when a project is becoming "design sloppy" and being able to forecast early and schedule time for the issues to be refactored.&lt;br /&gt;&lt;br /&gt;Most managers don't like refactoring.  It's unpredictable, and has no immediate beneficial output.  Experienced managers know that refactoring early is key to keeping a large code base manageable, and &lt;span style="font-weight: bold;"&gt;will &lt;/span&gt;save them time down the road.  Using software metrics, you can take such abstract and intangible notions, and turn them into hard numbers.  Those hard numbers can then be used for prediction, and prediction is the key to getting software estimates right.  This is the most vital step to get right for a &lt;a href="http://www.macadamian.com/"&gt;&lt;span style="font-weight: bold;"&gt;software outsourcing company.&lt;/span&gt;&lt;br /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Some useful tools for generating software metrics:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://metrics.sourceforge.net/"&gt;Eclipse metrics plugin&lt;br /&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://cccc.sourceforge.net/"&gt;CCCC (C++, Java)&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/macadamian/thefiles/~4/295887686" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/6946662272951619842/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=35928092&amp;postID=6946662272951619842" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/6946662272951619842" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/6946662272951619842" /><link rel="alternate" type="text/html" href="http://thefiles.macadamian.com/2008/05/software-metrics-what-are-they-and-what.html" title="Software Metrics : What are they, and what can they do for you" /><author><name>Mark Kotyk</name><uri>http://www.blogger.com/profile/09722975465820845708</uri><email>noreply@blogger.com</email></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35928092.post-3214601679232344701</id><published>2008-05-21T11:41:00.004-04:00</published><updated>2008-05-23T17:17:51.354-04:00</updated><title type="text">Transitioning from ASP.Net to JSP/J2EE</title><content type="html">&lt;span style="font-size:78%;"&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-style: italic;font-family:arial;" &gt;Note: This is my first blog post ever - and I call myself a web developer (I'm ashamed of myself... really I am).&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:arial;"&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-size:100%;"&gt;There is a sub title to this post, I like to call it a little tongue in cheekly:&lt;br /&gt;&lt;/span&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-size:130%;"&gt;half-whip-soy-mohca-latte dev frameworks vs single dev frameworks&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;  &lt;p style="font-family: arial;font-family:times new roman;" class="MsoNormal" &gt;&lt;span style="font-size:100%;"&gt;Having a very strong ASP.Net and MS development background as well as a significant amount of PHP and Perl programming under my belt, I thought transitioning to JSP/J2EE would be very simple, or at least not much of a challenge.&lt;/span&gt;&lt;span style=";font-size:100%;" &gt;  &lt;/span&gt;&lt;span style="font-size:100%;"&gt;I mean web development and development in general all subscribe to the same metaphors and design patterns, the only difference is the implementation details of the language and environment.&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="font-family: arial;"&gt;&lt;span style="font-size:100%;"&gt;Well, I couldn’t be more wrong.&lt;/span&gt;&lt;span style=";font-size:100%;" &gt;  &lt;/span&gt;&lt;span style="font-size:100%;"&gt;This transition has been tough.&lt;/span&gt;&lt;span style=";font-size:100%;" &gt;   &lt;/span&gt;&lt;span style="font-size:100%;"&gt;I write this blog as a small warning for people looking to do the transition from .Net to Java (and not necessarily the other way around) and might be a little overzealous or confident in how easy it might be.&lt;/span&gt;&lt;/p&gt;  &lt;p style="font-family: arial;font-family:times new roman;"  class="MsoNormal"&gt;&lt;span style="font-size:100%;"&gt;I truly believe that JSP + insert web framework here + J2EE is a good platform for web development and if you are looking for an argument in favor of one framework vs. the other, look elsewhere.&lt;/span&gt;&lt;span style=";font-size:100%;" &gt;  &lt;/span&gt;&lt;span style="font-size:100%;"&gt;The major challenge moving from a predominantly single web framework environment (ASP.Net) to a multiple web framework environment (JSP, Struts, JSF etc… &lt;a href="http://wicket.apache.org/introduction.html"&gt;see a lengthy list of web frameworks for JSP&lt;/a&gt;) is exactly that.&lt;/span&gt;&lt;span style=";font-size:100%;" &gt;  &lt;/span&gt;&lt;span style="font-size:100%;"&gt;There is no one rule book when you move to Java, there are &lt;i style=""&gt;many&lt;/i&gt; and one rule book will not necessarily tell you how you are going to choose your ‘flavour of the day’ half-whip-soy-mocha-latte framework.&lt;/span&gt;&lt;span style=";font-size:100%;" &gt;  &lt;/span&gt;&lt;span style="font-size:100%;"&gt;Some people will want JSP/Struts/Spring/Hibernate; some will want JSP/Struts and others JSP/Spring and others JSP/Spring/Struts/JSF trying to lean on the benefits of each framework.&lt;/span&gt;&lt;span style=";font-size:100%;" &gt;  &lt;/span&gt;&lt;span style="font-size:100%;"&gt;The challenge for an ASP.Net developer here is that these frameworks don’t just work together.&lt;/span&gt;&lt;span style=";font-size:100%;" &gt;  &lt;/span&gt;&lt;span style="font-size:100%;"&gt;You need to spend time figuring out how each of them will communicate and cohabitate in a fashion that will work and then you can start developing.&lt;/span&gt;&lt;span style=";font-size:100%;" &gt;  &lt;/span&gt;&lt;span style="font-size:100%;"&gt;This is huge paradigm shift, as suddenly you need to do some significant set up and tweaking to just get a web dev environment working.&lt;/span&gt;&lt;span style=";font-size:100%;" &gt;  &lt;/span&gt;&lt;span style="font-size:100%;"&gt;Furthermore, suddenly you have to start thinking about Application Servers, not just web servers.&lt;/span&gt;&lt;span style=";font-size:100%;" &gt;  &lt;/span&gt;&lt;span style="font-size:100%;"&gt;In the IIS+ASP.Net world, IIS will just about handle everything for you and an application servers were about architecture and scaling up or out using remoting or web services.&lt;/span&gt;&lt;span style=";font-size:100%;" &gt;  &lt;/span&gt;&lt;span style="font-size:100%;"&gt;In the JSP/J2EE world, your application server is NOT your web server, it’s something completely different – it’s a built in load balanced remote application server that can be separated from your web server with &lt;i style=""&gt;moderate ease&lt;/i&gt;.&lt;/span&gt;&lt;/p&gt;  &lt;p style="font-family: arial;font-family:times new roman;"  class="MsoNormal"&gt;&lt;span style="font-size:100%;"&gt;These two major paradigm shifts, once fully integrated into your knowledge help you take the small shifts that will come along, such as eliminating the event driven model of ASP.Net for whatever MVC model you go with for Java (some will be similar), or having to work update a number of xml configuration files to get Struts 2 up and running (And for any addition you make).&lt;/span&gt;&lt;span style=";font-size:100%;" &gt;  &lt;/span&gt;&lt;span style="font-size:100%;"&gt;Whatever your implementation troubles might be, keep in mind, these two software languages/frameworks/philosophies are very similar in concept but worlds apart in implementation.&lt;/span&gt;&lt;/p&gt;  &lt;p style="font-family: arial;" class="MsoNormal"&gt;&lt;span style="font-size:100%;"&gt;Hopefully this quick blog will help another ASP.Net developer stuck on a Java project transition just a little bit quicker or an ASP.Net developer looking at JSP and not jump in too quickly and find themselves drowning in the details.&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;span style="font-size:78%;"&gt;&lt;span style="font-family:arial;"&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="line-height: 115%;font-family:arial;font-size:11;"  &gt;&lt;/span&gt;&lt;/span&gt;&lt;img src="http://feeds.feedburner.com/~r/macadamian/thefiles/~4/295151234" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/3214601679232344701/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=35928092&amp;postID=3214601679232344701" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/3214601679232344701" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/35928092/posts/default/3214601679232344701" /><link rel="alternate" type="text/html" href="http://thefiles.macadamian.com/2008/05/transitioning-from-aspnet-to-jspj2ee.html" title="Transitioning from ASP.Net to JSP/J2EE" /><author><name>Tony</name><uri>http://www.blogger.com/profile/17596211212687907094</uri><email>noreply@blogger.com</email></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35928092.post-7283806696471420797</id><published>2008-05-14T16:14:00.009-04:00</published><updated>2008-05-16T09:31:01.270-04:00</updated><title type="text">Java programmer living in a C++ world</title><content type="html">Being a long time Java programmer, I've become familiar and fond of many of the features provided by the language. Reflection and runtime type identification add an extra level of power to any programming language. When I returned to C++ development, I found it necessary to fill the void I had grow accustomed to in the Java world.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Inversion of control in C++&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Inversion of control is a powerful design pattern (and/or philosophy) that allows for loosely coupled and highly reusable objects. The main principle is that an owner object is responsible for supplying all the needed information and resources to any object contained within. This includes configuration, initialization, logging, thread pools, databases and any other conceivable resource.&lt;br /&gt;&lt;br /&gt;When dealing with inversion of control, it's often desirable to test if a particular object implements a specific interface. An object may implement the &lt;span style="font-weight: bold;"&gt;Configurable &lt;/span&gt;interface, but not the &lt;span style="font-weight: bold;"&gt;Loggable &lt;/span&gt;interface. This is easy enough to do in Java using the "instanceof" keyword or via reflection. In C++, you must do things a bit different:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class Configuration;&lt;br /&gt;&lt;br /&gt;class Configurable&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt;virtual void configure(const Configuration &amp;amp;configuration) = 0;&lt;br /&gt;template&amp;lt;class&amp;gt;&lt;br /&gt;static bool tryConfigure(T *obj,&lt;br /&gt;                       const Configuration &amp;amp;configuration)&lt;br /&gt;{&lt;br /&gt;  Configurable *configurable = dynamic_cast&amp;lt;Configurable&amp;gt;(obj);&lt;br /&gt;  if (configurable)&lt;br /&gt;  {&lt;br /&gt;      configurable-&amp;gt;configure(configuration);&lt;br /&gt;      return true;&lt;br /&gt;  }&lt;br /&gt;  return false;&lt;br /&gt;}&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In this case, a owner object can attempt to configure a child object simply by calling the static method tryConfigure. If it the supplied object is of the wrong type, it will simply return false.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Configuration config;&lt;br /&gt;Configurable::tryConfigure( &amp;amp;ownedObjectA, config );&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The same can be applied for initializing and de-initializing objects.  Note that the static testing method is templated so the object type is not lost when passed in.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class Initializable&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt;virtual bool initialize(void) = 0;&lt;br /&gt;virtual bool deinitialize(void) = 0;&lt;br /&gt;&lt;br /&gt;template&amp;lt;class&amp;gt;&lt;br /&gt;static bool tryInit(T *obj)&lt;br /&gt;{&lt;br /&gt;  Initializable *init = dynamic_cast&amp;lt;Initializable&amp;gt;(obj);&lt;br /&gt;  if (init)&lt;br /&gt;  {&lt;br /&gt;      return init-&amp;gt;initialize();&lt;br /&gt;  }&lt;br /&gt;  return false;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;template&amp;lt;class&amp;gt;&lt;br /&gt;static bool tryDeinit(T *obj)&lt;br /&gt;{&lt;br /&gt;  Initializable *init = dynamic_cast&amp;lt;Initializable&amp;gt;(obj);&lt;br /&gt;  if (init)&lt;br /&gt;  {&lt;br /&gt;      return init-&amp;gt;deinitialize();&lt;br /&gt;  }&lt;br /&gt;  return false;&lt;br /&gt;}&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Singletons in C++&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Singleton is the most basic of all patterns, but extremely valuable. Care must be taken not to overuse singletons, but in the right place, they are a design gem. In C++ there is a simple template way to reduce the coding overhead of returning a static instance, and also unify the method names to get the instance.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;template &amp;lt;class&amp;gt; class Singleton&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt;  // Virtual destructor&lt;br /&gt;  virtual ~Singleton() {}&lt;br /&gt;&lt;br /&gt;  // Get instance as pointer&lt;br /&gt;  inline static Target *ptr(void) { return &amp;amp;(ref()); }&lt;br /&gt;&lt;br /&gt;  // Get instance as reference&lt;br /&gt;  inline static Target &amp;amp;ref(void) {&lt;br /&gt;          static Target theInstance;&lt;br /&gt;          return theInstance;&lt;br /&gt;  }&lt;br /&gt;protected:&lt;br /&gt;  Singleton(void) {}                              // Default constructor&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;To inherit a singleton object, one extra step must be taken so that the inherited constructor is called. That is to add the templated version of singleton as a friend to the class.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class MySingletonClass :  public Singleton&amp;lt;MySingletonClass&amp;gt;&lt;br /&gt;{&lt;br /&gt;friend class Singleton&amp;lt;MySingletonClass&amp;gt;;&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;NOTE:  Some compiler optimizations of a static inline method might cause undesirable effects, such as multiple instances of a singleton.  You may need to twiddle optimization flags.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Factories in C++&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Factories are responsible for creating objects of a specific interface type. For example, you could have a &lt;span style="font-weight: bold;"&gt;LoggerFactory &lt;/span&gt;that is able to create a &lt;span style="font-weight: bold;"&gt;PlainTextLogger&lt;/span&gt;, an &lt;span style="font-weight: bold;"&gt;XMLLogger &lt;/span&gt;and a &lt;span style="font-weight: bold;"&gt;SocketLogger&lt;/span&gt;. Unlike Java, in C++ it is difficult to dynamically create an instance of a class based on its name alone. By combining a Prototype pattern and a C macro, it is possible to register a class by name, and instantiate it later by name. This is somewhat analogous of querying an interface in Microsoft COM.&l