Saturday, December 6, 2008

Hexacta 6th in Great Place to Work 2008 ranking

The company I work for was recently distinguished as one of the top ten companies to work in Argentina (145 companies participated in the survey). This is more amazing if you take into account:

a) we all take the survey (does not matter if you are a functional analyst or manager or junior developer).

b) we are among giants in the top ten.

I am probably not the most involved guy in this (greetz go to Julio, HR, Diego, Juan, etc) but anyway it is nice to see the company being awarded again.

You can see the list here.

Federico

Smalltalk (and time available)

Today I set myself to start learning Smalltalk. For unknown reasons (availability, laziness, incompetence, who knows?) all of my OO teaching in university was using the venerable and powerful C++.

Years later I see that C++ while powerful on its own was probably not the right language to start with objects, it drags a big weight because of its C familiarity, so OO concepts might be a bit obscured by the language itself.

Being in Houston alone and without a car (Houston is amazingly not "walk friendly") I decided to see for myself what I missed in the past by learning some Smalltalk now. Probably it is not going to be the same experience, years of using other languages and platforms are probably an obstacle while trying to learn something new, previous experience clouds and blurs your ideas (like C++ clouded my vision of objects). Anyway I am willing to give it a try. According to Smalltalk gurus and followers my mind should be blown away and a whole new vision of objects may appear in front of me. I want to believe these people are not under the effects of any psychotropic (this guy's writing doesn't help the cause).

In any case, I am about to try two different environments.

Squeak (free and open source)

VisualWorks (free for non commercial use)

I know there's a Smalltalk implementation over the Net stack, including wrappers over the library to present it as standard Smalltalk library. I will try that later since I do not want to be diverted by other familiar stuff.

Right know I am in the hunting for good learning material ...

If my mind is blown away ... surely I will be writing about that.

Federico

Tuesday, October 28, 2008

Separation of concerns (SOC) articles

I have found the following articles from Jimmy Bogard about SOC. IMHO they are very good. I just thought about sharing the links to them.

Separation of Concerns - how not to do it

Separation of Concerns by example: Part 1

Separation of Concerns by example: Part 2

I hope you like them as much as I do.

Federico

Sunday, October 26, 2008

Converting your Canon video to see it everywhere

I have a Canon 570IS camera. A simple point and shoot model. It has the ability to save video that you can later download like you download the rest of the pictures.

The problem with these avi files is that they use a codec that is not installed into Average Joe's computer. The codec is called something like Picvideo MJpg, apparently a very fast encode/decode codec used by many photo cameras. The audio is encoded with standard PCM encoding. Full data for the avi file:

Video: MJPG 480x640 30.00fps [Stream 00]
Audio: PCM 22050Hz mono 352Kbps [Stream 01]

Now. I needed to send a video to someone who doesn't have the mjpg codec and doesn't know anything about computers. I do know that he (my brother) has a codec pack installed including xvid, one of my favorite codecs. Also, files using mjpg are not exactly light. One of my little videos of 35 seconds used 22.8MB so if I wanted to send the videos, I'd like to make them smaller. So the idea is to:

- Get smaller files

- Get files using a more friendly codec

To do this I used Virtualdub, a very well known video capture/processing program that I already had downloaded and the Xvid codec that I already have on my system.

One more thing. If you used the camera rotated to shoot the video, you can "straighten" it from the ZoomBrowser Ex (cool piece of software bundled with Canon cameras) or later, in this case I will do it later with Virtual Dub and one of its filters.

So I fire up Virtualdub and open the video file:

Capture1

You see the image of my brother rotated. This is the first thing I want to fix. I select Video - Filters - Add and from the list of filters I select rotate2

Capture2

(why not rotate alone? just because 2 sounded more advanced and says it is optimized ;) ). After clicking OK, a configuration dialog appears. At first I decided to go with 90 degrees of rotation and clicked on Preview, didn't work, my brother ended up head down like Spiderman. So I did -90 degrees and he was on his feet again ... but with an annoying black border. Clicking on Expand frame to fit took care of the problem. As for the Filtering mode I selected Bicubic 4x4, it is heavier on your CPU but you get better results (or so they say, I am not an expert). Image below

Capture3

With my brother oriented the way God intended to, I have to take care of compression.  As I said I will use Xvid. Go to Video, ensure that Full processing mode is selected and click on Compression, a list of available codecs will appear.

Capture4

Select Xvid Mpeg-4 Codec and click Configure. On the Profile @ Level dropdown select Portable, this will turn off some of the advanced stuff that we really don't need and keep everything compatible. You can check about profiles here. Select Two pass - 1st pass as the encoding option. The idea is that Xvid will collect information that will make the final result better by having pre-crunched information before the second pass. The negative side of this is that it will take longer to complete the whole process.

Capture5

The information that the pass is going to collect is stored in a file. One issue I found is that, by default Xvid shows something like \stats.pass when you click on the more button next to Encoding Type. This does not work, probably because of Vista's security feature, in any case, I prefer to have control of where the files are going to be created so I set the file path to the same folder where my end avi file is going to reside.

Capture6

Now click OK on everything and get to the main menu bar. Click File - Run video analysis pass. Depending on the CPU horse power this can take a while. Notice that the "pass" file storing the first pass info should be created where you selected it to be.

Now Xvid has information on what we want to compress. So go back to Video - Compression - Configure. The Xvid options should be visible again. Select Twopass - 2nd pass leave the Target size as it is. Now go to the File - Save AS AVI select the file name and folder and click on Save. Depending on your power this can take a while but you will get your AVI with Xvid file. In my case not only the Xvid compression is taking place, but also the rotation.

Check out the size :)

Capture7

And if you mind about quality (you should not ... you are recording with a photo camera!!) check the following picture (click to enlarge)

before-after

Original - Xvid compressed

This was all done with default options. You can also tweak the Target size if you want to get a smaller file, and also resize the video on the fly with a resize filter in Virtualdub.

Federico

 

  

Monday, October 20, 2008

How to speed up XmlSerializer (sgen)

A couple of weeks ago I had to use the XmlSerializer. I used it before almost for the same reason. To exchange information between some systems. In my particular case I was using very simple DTOs. In case you don't know it, the XmlSerializer is known for being slow. When you ask for an instance of the serializer using the DTO type in the constructor, there is some process going on behind the scene. All of this happens the first time you ask for the instance.

  1. The serializer checks to see if it is a known serializer (it maintains an internal cache). Being the first time you ask for this type it won't find anything.
  2. The type you sent gets reflected to death inside the System.Xml.Serialization namespace. Information is gathered from your classes (public properties, fields, attributes to modify the schema, etc). All of this is stored in mapping information.
  3. With all the mapping information. The serializer proceeds to create code (yep to create it) using the facilities provided by a CodeDomProvider, in this particular case, the CSharpCodeProvider.
  4. The new code which include functionality to serialize and deserialize is compiled (all of this because you instantiated a serializer...) and the result is a temporal assembly usually named [your type].XmlSerializers. The name might be followed by some number under some circumstances but usually you won't see nothing there. Remember this is the name of the assembly not the name of the dll file. If you use some tool like Process Monitor you will be able to see csc (the C# compiler) launching when you instantiate your serializer. In my case I see something like:
"C:\Windows\Microsoft.NET\Framework\v2.0.50727\csc.exe" /noconfig /fullpaths 
@"C:\Users\Flaker\AppData\Local\Temp\mhxapuui.cmdline"


This is of course a completely temporal path and name.

So as you see the problem here (if you decide there is one) is that creating an XmlSerializer for a given type is very resource consuming. It won't probably bring down your machine but since there is an easy way to improve you might want to give it a try.



You see, the steps I numbered first are not complete. Before trying to create new code, the XmlSerializer is smart enough to try to see if there is any pre-created serializer/deserializer assembly for the given type. You must provide this assembly, and you do it by using the sgen tool. You will find this tool in the bin folder of your SDK.



The sgen tool basically makes use of stuff already present in the framework. It does not create code by its own but uses the static call to XmlSerializer.GenerateSerializer static method. As an example, this is a command line:



C:\Users\Flaker\Spikes\TestSerializers\TestSerializers\bin\Debug>sgen /a: MyDtos.dll /k



The reason I added the /k is because I am curious and this flag will keep the temporary files that are otherwise deleted. You can see the output of the command line:



image



and the list of files. Including the temporary files (in this case they start with "fdyxy6-l.0").



 image



The important result there is the file MyDtos.XmlSerializers.dll. That files includes the methods to serialize and deserialize your types. Just by including it the instantiation process of XmlSerializer won't create a new one.



In fact, if you want to, instead of using the regular XmlSerializer you can use the new class inside the new assembly. So your code



image



turns into



image



So just with a simple command line call or post build script (if you need that) I get a lot more speed without effort.



Federico

Wednesday, October 15, 2008

Translation bot for Live Messenger

Yesterday I listened to a very interesting podcast by Scott Hanselman. It included a nice talk about a research work at Microsoft. One of the results of that research is a bot for Messenger that you can use to:

  • Get translations
  • Talk (well ... write)  to other contacts in your contact list in their native language using the bot as a middle man translator.

Test it, you just have to add mtbot@hotmail as a contact. Check the window capture below to see a sample.

image

 UPDATE: type "tbot ?" inside the window to get some help (without the quotes ... obviously)

Tuesday, October 14, 2008

Using a custom bootstrapper

I am not an expert in setup projects and all the intricacies of MSI. I usually work on my application and later arrive to the awful truth of setup projects. Visual Studio setup projects are simple and not incredible powerful, it does not offer the raw power exposed by Wix but gets the job done most of the time and it's simple to use (in simple scenarios).

A couple of days ago I confronted the need to do something a bit more complex. I needed to install two MSI files from the Microsoft Synchronization Framework that went RTM a couple of months ago.

My first idea was to use Launch Conditions. They are offered right there in the setup project. Basically you create some kind of condition (for example "Is sync framework installed") and if it fails the setup process will offer to install it from an URL.

Sounds good, but if you have to install a couple of things, it is really a bad experience for the end user because after installing one package, the setup program exits. So if you have to install 3 required packages, it will exit three times. Other thing that bothered me is that some people had an earlier version of the program installed with a CTP version of the framework and I really wanted to get rid of that CTP version. Usually can be done, but not so easily with a Visual Studio setup.

The next step and always with simplicity in mind was to create a generic bootstrapper. You probably have seen those but maybe you don't remember. When you click on Setup - Properties - Prerequisites you see a list of bootstrappers to select from (see the image below).

image

The idea is to add the new bootstrapper there. I decided on the creative name of "Blog Sync Framework Runtime V1.0 RTM".

To create a bootstrapper you need at least two files called manifests. One will be called product.xml and the other (or others depending on the languages you support ) will be called package.xml. The appropiate layout for the files is shown in the next image.

image

Your bootstrapper will live inside your sdk. In my case, the path is

image 

You can find the path programmatically (if you need to do so) in the registry under

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\GenericBootstrapper\3.5

I will go through product.xml section by section.

Header

<?xml version="1.0" encoding="utf-8"?>
<Product ProductCode="Blog.Sync.Framework.Runtime.V1.0.RTM" xmlns="http://schemas.microsoft.com/developer/2004/01/bootstrapper">

These first couple of lines are the xml header and the root element for this xml file. All the xml files included here use the same namespace and editing them in Visual Studio is simpler given the Intellisense help. ProductCode will identify your product to other products. This string will not be shown to the user so choose a meaningful name to you and other programmers.


Related Products (depends and provides)



<RelatedProducts>
<DependsOnProduct Code="Microsoft.Net.Framework.3.0" />
<DependsOnProduct Code="Microsoft.Windows.Installer.3.1" />
</RelatedProducts>


Related products in this case shows products we depend upon. See how the Code attribute refers to a ProductCode like the one I chose before. I can also include what my packages are already providing but I won't. The values assigned to the Code attribute are very easy to find inside the other packages, just snooping around.


Package files


<PackageFiles CopyAllPackageFiles="false">
<PackageFile Name="synchronization.msi"
PublicKey="3082010A02820..." />
<PackageFile Name="providerservices.msi"
PublicKey="3082010A02820..." />
</PackageFiles>

These are the actual MSI files I need to get installed. This element has plenty of attributes to choose from, there is a link to the complete schema at the end of the article. I took the simpler path here, I am including the redistributable packages and including the PublicKey even if it is optional right now. It is mandatory if I decide to download the MSI files from an URI using the HomeSite attribute. I got the public keys from other bootstrappers since that seems to be Microsoft key for redistributable MSI files. Beware that the keys are reeaaalllly long so I trimmed them down in the text (they are complete in the downloadable package). BTW, the CopyAllPackageFiles attribute instructs the bootstrapper to download all the files even if they are not going to be used. I am not downloading anything here and I don't need anything I do not have, so I set it to false.


Check what is installed


You don't want to install your prerequisite packages every time the user runs setup. And may be you want to check if something else is installed. There is plenty of mechanisms to check for installed products, file presence, registry keys, etc. In my case I only have to check if the Sync Framework packages are already installed.


<InstallChecks>
<MsiProductCheck Property="IsRuntimeInstalled" Product="{A8BD5A60-E843-46DC-8271-ABF20756BE0F}" />
<MsiProductCheck Property="IsProviderInstalled" Product="{03CAB33F-D1C2-48C6-8766-DAE84DFC25FE}" />
</InstallChecks>


I am using one of the mechanisms provided: the MSI product check. You may not know it but every product has a product key associated with it. To get it you can use programs such as msiinv or Orca, both included with the SDK. An Orca screen capture is below:


image


The product code is highlighted.


Install! (if needed)


So the MsiProductCheck creates a property that I am going to use later based on the presence of an MSI product with a given key.

<Commands Reboot="Defer">
<Command PackageFile="synchronization.msi">
<InstallConditions>
<BypassIf Property="IsRuntimeInstalled" Compare="ValueGreaterThanOrEqualTo" Value="3" />
</InstallConditions>
<ExitCodes>
<ExitCode Value="0" Result="Success" />
<DefaultExitCode Result="Fail" String="UnexpectedCode" FormatMessageFromSystem="true" />
</ExitCodes>
</Command>
<Command PackageFile="providerservices.msi">
<InstallConditions>
<BypassIf Property="IsProviderInstalled" Compare="ValueGreaterThanOrEqualTo" Value="3" />
</InstallConditions>
<ExitCodes>
<ExitCode Value="0" Result="Success" />
<DefaultExitCode Result="Fail" String="UnexpectedCode" FormatMessageFromSystem="true" />
</ExitCodes>
</Command>
</Commands>

This section is actually where you decide what to install and what to do if it fails. Reboot is set to defer because in fact we do not wish to force the user to reboot. Check that we have a Command for each package. We make use of the properties created earlier in the InstallConditions. Basically if my check returned a value greater than 3, I assume the package is installed so I do not need to install it again. The value "3" sound kind of like a magical number but has a good explanation. If you look for msi.h in your SDK folder you can find an enum with the following values.


enum tagINSTALLSTATE
{
INSTALLSTATE_NOTUSED = -7, // component disabled
INSTALLSTATE_BADCONFIG = -6, // configuration data corrupt
INSTALLSTATE_INCOMPLETE = -5, // installation suspended or in progress
INSTALLSTATE_SOURCEABSENT = -4, // run from source, source is unavailable
INSTALLSTATE_MOREDATA = -3, // return buffer overflow
INSTALLSTATE_INVALIDARG = -2, // invalid function argument
INSTALLSTATE_UNKNOWN = -1, // unrecognized product or feature
INSTALLSTATE_BROKEN = 0, // broken
INSTALLSTATE_ADVERTISED = 1, // advertised feature
INSTALLSTATE_REMOVED = 1, // component being removed (action state, not settable)
INSTALLSTATE_ABSENT = 2, // uninstalled (or action state absent but clients remain)
INSTALLSTATE_LOCAL = 3, // installed on local drive
INSTALLSTATE_SOURCE = 4, // run from source, CD or net
INSTALLSTATE_DEFAULT = 5, // use default, local or source
}

So as you see a value from 3 and up is good to us. Lower values represent problems.


If the component is installed you can expect a return value (that is common behavior right?), usually a 0 means OK and something different means a failure. We represent that with the ExitCode and DefaultExitCode elements. See how an arbitrary string "UnexpectedCode" is provided when failing. Of course such a string cannot be shown to the user. So how do we manage to present the user with a (somewhat) meaningful message? by using the other file, package.xml of course. I will paste the complete file.


<?xml version="1.0" encoding="utf-8"?>
<Package Name="DisplayName" Culture="Culture" xmlns="http://schemas.microsoft.com/developer/2004/01/bootstrapper">
<Strings>
<String Name="Culture">en</String>
<String Name="DisplayName">Blog Synchronization Runtime v1.0 RTM</String>
<String Name="UnexpectedCode">The installation failed (unexpected code was returned)</String>
</Strings>
</Package>

See how "UnexpectedCode" gets defined for the selected language (english). There are also other definitions, for example Culture is defined to "en" and DisplayName is assigned the value "Blog Synchronization Runtime V1.0". That Display name is the one that will appear in your prerequisite dialog, so choose something meaningful. Being this file for a specific culture, it resides on a specific folder "en" as you can see on a previous screen capture.


After you get your product.xml and package.xml along with the MSI files. Copying the whole package to your bootstrappers folder will be enough to show the new option in the setup project properties. Check the screen below:


image


Our bootstrapper is available and if you run setup you get a screen like the following.


image


You can get the complete bootstrapper here and test setup here (Skydrive links).


The schema reference for the manifests is here if you want to check it (a lot of useful stuff).



Federico.