Every day for the 2 weeks leading up to to Christmas, imason gave each employee a small gift. One of the gifts was something of a "confetti canon". A few colleagues and I had wars between us and on one occasion I videotaped Boyan shooting the confetti in a senior co-worker's office.

I wanted to try out Windows Movie Maker, so I put together a short clip of the confetti shooting coupled with some Benny Hill music (The idea for the music came from the Benny Hillifier - a site where you can take any YouTube video and apply Benny Hill's Yakety Sax to it).

Using Windows Movie Maker, it took only 10 minutes to make this short video (The haste in which I created the video will quickly become apparent when you watch the video). Although Windows Movie Maker has a couple neat features, I still prefer Corel/Ulead's VideoStudio Professional which I used to create my Summer 2008 video. The price tag of $79.99 is well worth it, but Windows Video Maker is free so if you don't need the extra features provided by VideoStudio, Windows Movie Maker might do the trick.

Here's the short movie clip that I've entitled "Fun at imason":

 

 

Filed under: , ,


Many of my co-workers here at imason are University of Waterloo alumni. I often hear people talking about Waterloo Economics Associate Professor Larry Smith. He's apparently a very knowledgeable and entertaining professor, but I didn't have the privilege to attend Waterloo.

Somebody posted a "Larry Smith Lingo & Prof Quotes" page and although these are probably more entertaining for those who have attended his classes, I still found them to be very amusing anyway. Here are my favourite 11 quotes:

  • I'm sorry, ladies and gentlemen; we're finishing this course come hell or heart attack
  • You can go to the Bank of Canada website and look up these numbers [about forms of money]. It's more fun than visiting a porno site.
  • People who have REAL lives get hundreds of email messages a day. How do I know you're a real person? When I ask you how it's going and you say: Damn email's driving me crazy! Yes! You've reached manhood!
  • Maybe I should fall down and break my neck. That would be entertaining
  • Masturbation is merely the act of making love to the one you love best.
  • I'm a legend in my own mind.
  • Beware, beware, danger there lurks. Warning, warning, run in the other direction...
  • Americans know of only two countries America and Not-America.
  • A person who can see in the land of the blind will be king
  • I wonder where she [Buffy the Vampire Slayer] was in my highschool. . .all my teenage fantasies rolled together.
  • I don't need to impress you, I impress myself
Filed under: ,


While working on my .NET State Machine workflow today, I ran into an issue: I wanted to send an e-mail to a user every XX days to remind them to finish filling out a form, and I wanted those e-mails to continue being sent until the form had been filled out.

At first I thought this would be a simple While Activity with a Delay Activity timer inside it, but a Delay Activity has some limitations: I originally added it to my StateInitialization Activity, but it can’t be used inside a StateInitialization Activity because it inherits the IEventActivity interface. This also means that you can only use a Delay Activity as the first Activity in an EventDriven Activity, which prevents you from putting a Delay Activity inside a While loop.

So I took a quick look at other people running into the same issue and found this user group discussion, but I didn’t see any viable solution for repeating the Delay Activity indefinitely.

So to solve this, I added a new EventDriven Activity to my State Activity and set the Delay Activity as the first Activity in the EventDriven Activity.

clip_image002

Then I added an IfElse Activity to check if the form had been filled out or not. If the form is filled out, I change the state to “CompleteState”. But if the form hasn’t been filled out, I set it back to the current state which will re-trigger the EventDriven Activity, thus re-starting the Delay timer.

clip_image004

It will continue this loop until the form is filled out, sending an e-mail every time it executes. This is exactly the functionality I was looking for, but the approach to accomplish this was slightly different than I had expected.


In my 6+ years in the software development business, I’ve used a variety of techniques for performing developer knowledge transfers. When I hold a knowledge transfer session, I like to set my own objectives (What am I hoping to get out of the session?), familiarize myself with the objectives of my audience (What is my audience looking to achieve?), know the audience’s skill level (If I move quickly, will they be able to follow?), and I like to be familiar with the logistics (Have I booked a training room? Do I have sufficient hardware? Software is installed? Do I have Admin privileges?)

When your audience is large, the technique is much different than when the audience is small. It’s more difficult to completely engage a larger audience, so the key is to do hands-on training to ensure your audience is following along. I’ve done sessions that weren’t hands-on, but they were far less effective than the hands-on sessions, and are usually a result of time/logistics constraints than anything else.

To date, my most effective developer knowledge transfer session involved choosing 2 or 3 small feature enhancements (Or bugs), and using a “Pair Programming” approach to develop these features. This obviously works best in a pair (i.e. training 1 other person), but I think it can also be effective for training up to 3 developers. Using a meeting room on a projector, each developer would take turns writing some code. This keeps them engaged and when they aren’t writing code they stay focused because they need to know what is happening for when it’s their turn to write the code.

I feel that this is the absolute best way for new developers to learn about the code, and it’s the most rewarding way for the developer(s) who wrote the code to showcase his/her code. In addition to the learning benefits, you are also using your time efficiently by actually addressing a new feature or existing bugs. If you’re on tight deadlines, this approach allows you to keep the project moving forward while transferring knowledge at the same time. The last benefit of this approach is you can incorporate a code review into the session by getting an objective viewpoint from the developers you are transferring the knowledge to (Assuming the recipients are experienced enough to have constructive suggestions).

In summary, the benefits of hands-on knowledge transfer are as follows:

·         Productivity in that the project keeps moving forward (Tight project deadlines are a reality in our industry)

·         Hands-on learning for the recipients (Make sure to use proper source control in case something goes wrong J)

·         Simultaneous code-review (Find all those divide by zeros)

·         Better focus from the participants (Nobody falls asleep)

Filed under:


Over the years, India has evolved from being a cheap-labour offshore destination in the late 90's to becoming a premier full-range IT services destination in the 21st century. The primary reason for this trend is the highly educated and English-speaking workforce in India, as well as their hard work ethic and enormous population.

In the early 2000's, India had achieved some great accomplishments in the area of software quality; 75% of the world's CMM Level 5 software centres were in India (At the time, CMM Level 5 was known as one of the highest levels in standards of quality).

Offshoring has not been without difficulties. Many projects that I've personally been an observer of have not lived up to expectations, mainly as a result of miscommunications or lack of sufficient business requirements. I can imagine how difficult it would be to get clarification on business requirements with the time zone differences and the long distance. Technology consulting companies have enough difficulties as it is even when having the luxury of a nearby client.

But alas, the point of this article was not to delve into the pros and cons of offshoring, but to point out how India's services have evolved over the years.

Just today, the Pittsburgh Pirates have signed two 20-year old Indian baseball players who have never played baseball. Rinku Singh and Dinesh Patel took part in a pitching competition reality TV show in India sponsored by a California sports management company, who awarded Singh $100,000 and Patel $2,500 for winning the contest.

The Pittsburgh Pirates are hoping to teach these young men how to play baseball in the minor leagues in the hopes they could become Major League pitchers in 3-4 years. Being cricket players, they weren’t accustomed to wearing a baseball glove, so they had to be taught not to catch the ball with their bare hands.

In our world of globalization companies both inside IT and outside IT are scouting the global pool of talent to find the best and the brightest people. The Pittsburgh Pirate recruitment from India is symbolic of the direction business is headed in our ever-shrinking world, and countries like China and India will become more than just offshore destinations, they will open the door to many new possibilities previously untouched.


A bunch of us at imason are taking part in Movember to raise awareness and raise money for Prostate Cancer.  For those of you who aren’t familiar with Movember, the idea is that you grow a moustache during the month of November to raise awareness for men's health. I don’t want to say that we’re “embarrassing” ourselves to raise money, because that could be perceived as a shot against people who normally wear a moustache.

There  is nothing wrong with having a moustache, but for those of us who don’t normally wear a moustache, it is a bit embarrassing (but fun at the same time).

It’s interesting to me how everyone looks completely different when they grow a moustache. My co-worker Boyan looks like Freddie Mercury, Rez looks like a scary hitman, Shahzad looks like a Venice Taxi Paddler and Steve looks like a Medieval Viking.

I wasn’t sure what I would look like until I trimmed up today. Due to my inept ability to grow hair on my face combined with my “overtrimming”, I unfortunately ended up looking a bit like Adolf Hitler.  I have one more week remaining to let it “thicken out” a bit. Hopefully by the end of the month I’ll look more like Tom Selleck.

 

Filed under:


At imason, we generally enjoy conversations about a wide variety of topics, whether it be at the water cooler, on an e-mail alias, over lunch, or conversations at our desks. Our Co-CEO, Scott Howlett even hosted some lunch election roundtables where we discussed the issues of the Canadian election, dissected each party's stance on the issues, and heard each other's opinion on whether their platforms would be effective. They were very stimulating conversations.

As readers of my Urban Country blog know, I'm very passionate about Politics and the Environment, so it was a treat for me to have in depth discussions about these things at work where we generally don't engage in these sort of topics.

One topic that has come up a few times over the last few weeks is the conversation about divisive politics. In the United States political system, there is a lot of "us vs. them" or "you're with us or you're against us" or "Republicans vs. Democrats" or "Red States vs. Blue States" or "Capitalist vs. Communist", and the list goes on.

A more recent conversation led to the question of "Agile" vs. "Not Agile" when it comes to project methodologies. At imason, we have our own project methodology, and we try to employ components of other methodologies where we think it will help to improve our process. The way we see it, Agile isn't binary. A methodology can become more agile or less agile simply by tweaking the approach.

I had a great opportunity this spring/summer to work with some very talented developers from ThoughtWorks out in Calgary. They were on the more "Extreme" side of Agile software methodologies (Literally, they use the Extreme Programming (XP) approach developed by Kent Beck). Like any software development methodology, Extreme programming has its advantages and disadvantages. The purpose of this article isn't to delve into such an analysis, but to point out some of the neat aspects of their methodologies that I've taken with me back to Toronto.

First of all, I'm a huge advocate of automated builds and continuous integration. I've been pushing this on all of the projects I've worked on and NAnt has helped us achieve great things in the world of automated deployment. Secondly I am a big fan of the disciplined approach to project management (Mostly from the Scrum methodology), including set daily standup meetings, timeboxing, story cards and story boards.

But perhaps the most interesting aspect of the Agile approach that I've taken away is incorporating "fun" into your project discipline. Some examples include bringing in a box of doughnuts if you break the build, doing pushups if you're late for a meeting, or hanging a rubber chicken around your neck.

At imason, we work hard to dramatically impact our customers and ourselves, and if you can have fun while you're working hard, that's the most important way to achieve success. To me, success isn't measured by what kind of car you drive or how big your house is; it's about spending your day with people you enjoy being around, and doing work that gives you satisfaction. It's about waking up in the morning and not dreading going into work.

Filed under: ,


As many of you probably already know, Silverlight 2 was released in the wee hours of the morning (3AM EST or 12AM Microsoft-time). We've noticed some inconsistencies with the upgrade process from Silverlight 2 Beta 2 to the Silverlight Release, so I figured I would share our findings with you here.

It looks like there was an issue with the Silverlight Auto-Updater in Silverlight Beta 2, so a Windows Update was pushed this morning to rectify the auto-updater. The windows update pertains to Microsoft Support article KB955011.

As a result, users who didn't install the Windows Update yet were prompted with what I call a "not-so-intuitive" upgrade process for Silverlight 2. They basically have the same experience as users who don't have Silverlight at all:

Those who did install the Windows Update will see what I call the "More-intuitive" image:

So to accommodate for those users who didn't install the update, we've created our own custom image that explains why Silverlight has to be updated:

So now everything should be as smooth as we can expect it to be.



MacLeans recently ran an article about the Top 100 places to work in Canada. After reviewing the perks that a lot of the top companies were providing to their employees, it really surprised me that imason isn't on that list. At first I thought maybe it was because we are too small (We have approximately 36 full time employees), but then I noticed there were several companies with less than 30 employees that made the list. We must not have applied to make the list; otherwise I’m sure we would have been listed.

Here are some of the perks that we have at imason (that we sometimes take for granted):

·         Paid birthdays off (if it falls on a weekday)

·         Annual company trip to Canadian destination (Usually a 3-4 day trip)

·         Paid week between Christmas and New Years off

·         Free Home Internet and subsidized Cell Phone

·         Pool table, XBox and beer fridge at office

·         Profit Sharing program

·         Vacation starts at 3 weeks (In addition to Christmas break / birthday / company trip)

·         Monthly Gym membership / sports activity coverage

·         Fundraiser matching for charity work

·         Subsidized training / education for career growth

·         Comprehensive benefits plan for employees / spouses and family

These are some of the things that I think could put us on the list. But for the time being, we'll enjoy our beer fridge and pool table while the employees at Procter & Gamble can keep their 3 paid personal days off and their health benefits transfer plan.


We’ve now surpassed 50 InfoPath forms on the InfoPath 2007 / SharePoint 2007 project I’m currently engaged on. If you’ve done InfoPath/SharePoint development before, you’ll know that it can be really painful to publish forms and then deploy them to SharePoint.

In Part 1 of this 2 blog series, I showed you how to automate the deployment of InfoPath forms to SharePoint using NAnt. This time around I’ll show you how to automate the publishing of an InfoPath form.

If you’ve published an InfoPath form to an Administrator-approved form template before, you’ll be all too familiar with the process of clicking next a whole bunch of times in order to publish the form. Why should you have to go through all these manual steps every time you make a change to a form?

To automate this, I first found some VB code on this blog article to publish a form. I then converted it to C#, and built it as a custom NAnt task. So now I can publish a form by simply calling a custom NAnt task like this:

<publishform outputfolder="c:\mypublishedforms" formname="MyFormName.xsn" cabsdkpath="..\tools\CabSDK\BIN" xsffilename="manifest.xsf" formsourcepath="..\trunk\src\SourceForms\MyFormName\InfoPath Form Template\" />

In order to use this approach, you’ll need to either build your InfoPath form using the Visual Studio template, or you’ll need to extract the form source files from the XSN. To extract the source files from the XSN, choose “File” -> “Save As Source Files”. Then you can work with your form template by right clicking on “manifest.xsf” and choosing “Design”.

Here is the code to build the custom NAnt task:

using System;

using System.Diagnostics;

using System.IO;

using System.Xml;

using NAnt.Core;

using NAnt.Core.Attributes;

 

namespace My.Build.Tasks

{

    [TaskName("publishform")]

    public class PublishFormTask : Task

    {

        [TaskAttribute("outputfolder", Required = true)]

        public string OutputFolder { get; set; }

 

        [TaskAttribute("formname", Required = true)]

        public string FormName { get; set; }

 

        [TaskAttribute("cabsdkpath", Required = true)]

        public string CabSdkPath { get; set; }

 

        [TaskAttribute("xsffilename", Required = true)]

        public string XsfFileName { get; set; }

 

        [TaskAttribute("formsourcepath", Required = true)]

        public string FormSourcePath { get; set; }

 

        protected override void ExecuteTask()

        {

            string makeCabPath = CabSdkPath + "\\MAKECAB.EXE";

            BuildCabFile(makeCabPath);

        }

 

        private void BuildCabFile(string makeCabExe)

        {

            try

            {

                if (!File.Exists(makeCabExe))

                {

                    throw new Exception(string.Format("CABSDK not found. Please check your CABSDK property value. Couldn't find makecab.exe @ '{0}'", makeCabExe));

                }

 

                var tempName = Path.GetFileNameWithoutExtension(Path.GetTempFileName());

                //var tempName = Path.GetTempFileName();

                var tempFolder = Path.GetTempPath();

                var tempPath = PathCombine(tempFolder, tempName);

 

                var ddfString = string.Empty;

                ddfString += ".Set DiskDirectoryTemplate='" + tempFolder + "'" + Environment.NewLine;

                ddfString += ".Set CabinetNameTemplate='" + tempName + "'" + Environment.NewLine;

 

                var xsfDom = new XmlDocument();

                xsfDom.Load(PathCombine(FormSourcePath, XsfFileName));

                var nm = InitNamespaceManager(xsfDom);

 

                ddfString += QuoteString(PathCombine(FormSourcePath, XsfFileName)) + Environment.NewLine;

                var fileNodes = xsfDom.SelectNodes("/xsf:xDocumentClass/xsf:package/xsf:files/xsf:file/@name", nm);

 

                for (int i = 0; i <= fileNodes.Count - 1; i++)

                {

                    ddfString += QuoteString(PathCombine(FormSourcePath, fileNodes[i].InnerText)) + Environment.NewLine;

                }

 

                var ddfPath = PathCombine(tempFolder, "makecab.ddf");

                SaveToFile(ddfString, ddfPath);

                ShellExecute(QuoteString(makeCabExe), "/V1 /F " + QuoteString(ddfPath));

                File.Delete(ddfPath);

 

                if (File.Exists(PathCombine(OutputFolder, FormName)))

                {

                    File.Delete(PathCombine(OutputFolder, FormName));

                }

 

                File.Move(tempPath, PathCombine(OutputFolder, FormName));

 

                string[] oScratchFiles = new string[] { "setup.inf", "setup.rpt" };

                foreach (string strScratchFile in oScratchFiles)

                {

                    if (File.Exists(strScratchFile))

                    {

                        File.Delete(strScratchFile);

                    }

                }

            }

            catch (Exception ex)

            {

                throw new Exception("Could not create XSN file from files.", ex);

            }

        }

 

        private static void SaveToFile(string data, string filePath)

        {

            var fs = File.Create(filePath);

            fs.Close();

            var TextStream = new StreamWriter(filePath);

            TextStream.Write(data);

            TextStream.Flush();

            TextStream.Close();

        }

 

        private static void ShellExecute(string command, string args)

        {

            var info = new ProcessStartInfo(command, args);

            info.UseShellExecute = false;

            var process = Process.Start(info);

            process.WaitForExit(60000);

        }

 

        private static string QuoteString(string s)

        {

            return "\"" + s + "\"";

        }

 

        private static string PathCombine(string folder, string fileName)

        {

            return Path.Combine(folder, fileName);

        }

 

        public static XmlNamespaceManager InitNamespaceManager(XmlDocument xmlDOMDoc)

        {

            XmlNamespaceManager xnmMan;

            xnmMan = new XmlNamespaceManager(xmlDOMDoc.NameTable);

 

            foreach (XmlAttribute nsAttr in xmlDOMDoc.DocumentElement.Attributes)

            {

                if (nsAttr.Prefix == "xmlns")

                    xnmMan.AddNamespace(nsAttr.LocalName, nsAttr.Value);

            }

 

            return xnmMan;

        }

 

        public void RunTask()

        {

            ExecuteTask();

        }

    }

}