I Love ReSharper

Wed 24 January, 2007

This was going to be a post about the different VS 2005 plugins that I use, and some other useful programs for my everyday (most of them Open Source, by the way); but while I was writing it turned itself little by little into a love letter to Resharper. I can only say good things about this productivity plugin.

This are only some of its features:

  • Automatic warning and error checking while you write code; similar to the automatic ortographic revision from MS Office but quite more smart.
  • Better Intellisense. By far, my preferred feature and the one you tend to note first. If you want it to, ReSharper can completely replace VS2005’s Intellisense with its own, faster and more complete. You have the possibility of setting the same font for Intellisense and source code, you can replace Intellisense icons with ReSharper’s set, and add a pop-up with the complete method signature.
  • Code auto-completing, you write the first three characters of virtually anything and ReSharper is already displaying a list of alternatives. If what you’re writing is a method call, pressing TAB inserts the complete method name along with the () and the ;.
  • Templates.
  • Refactoring: you can extract properties from variables, or methods from code: you select a code block, select to extract it as a method, give to it a name and some options, among them are a list of possible parameters that ReSharper automatically detects and voilá!: method created.
  • Advanced search for method use.
  • Type hierarchy view
  • Unit test running with NUnit or csUnit from the IDE.
  • Context actions. In some sections of your code you can see a small floating window with a lightbulb icon. ReSharper wants to help: opening that window with your mouse (or even better, pressing ALT+Enter) ReSharper will show you a list of all the possible actions it can make depending on the code context: check for null values, reorder if sentences, refactor string concatenatios with an StringBuilder, delete unused references, and so on.
  • Automatic detection of unused variables, methods or references. If you declare a variable at the beginning of your code that you later don’t use ReSharper will remark it using a grey color (trust it, it’s quite more noticeable than it sounds), and with that you know that it’s not being used anywhere. ReSharper uses the same color to remark redundant and useless casts or uses.
  • Quick jump to a method or variable definition: using CTRL+Click on the method or variable name you can jump directly into the method or variable definition, if the code is avaliable.
And these are only the tool’s highlights, the tasks I do daily with it. Definitely, it’s the best buy I’ve ever made for a Visual Studio add-in; mostly because I used this last Christmas offer and got it for $99 instead of its normal price tag of $249, which is quite unexpensive if your firm buys it for you: not my case. I bought ReSharper for my exclusive use.

JetBrains development team make Visual Studio 2005 a better yet IDE with this product. The ongoing rumor that they are developing their own version of a .NET IDE, building of IDEA’s true and tested success is, sadly, outdated (look the comments), because it seems the project is abandoned. A real pity.

VirtualBox

Tue 16 January, 2007

When I was beginning in software development, I worked for a firm which (among other things) sells a software application for creating plastic cards. That software was off-the-shelf, shrinkwrapped.

As you can see, the software had to be able to install itself easily and couldn’t use additional components. To make sure of it, every time we compiled a new distributable version we made compatibility tests: on my desk I had four machines, one for development and three older PCs for tests. One of the machines had a Windows 95, another a Windows 98 and the last one a Windows NT; and each of them had only that and the necessary drivers installed. Our software had to work on naked machines, and with each major upgrade we had to format the test machines and reinstall their operating systems, to make sure a perfect installation of our application. The process was so repetitive that I ended unwillingly memorising the serial numbers of each OS.

We managed to speed up the process quite a bit thanks to Norton Ghost: you could make an "naked" OS image file for each machine and after the installation tests of our application, we could reinstall the software from the Ghost image, which quite faster and automatic.

But it was still a pain.

I would have been really happy those days for virtual machine software: either it didn’t exist by that time or I didn’t know about it. For those of you who don’t know what I’m talking about, Para los que no sepáis de lo que hablo, las virtual machines are programs that create a virtual environment between your physical hardware and the operative system installed in that hardware; and in that virtual space you can install another operative system completely different to the one physically installed, in a completely sandboxed environment. You can have a Windows 2003 Server inside a Windows XP, for example.

It’s easier to do than it looks: you assign inside the hard drive of your machine a file that’s going to be the virtual machine hard drive; and you set an amount of RAM to the virtual machine (RAM that’s going to be substracted from your total, physical RAM avaliable, so you need to have plenty for this). You can also mount virtual CD or floppy drives, allow the virtual machine network access, etc. To install an OS you just have to mount an ISO file containing an auto-bootable OS and run the virtual machine. From that point, you simply follow the OS installation instructions as if, in fact, we were installing a new OS in a machine built inside our machine.

I’ve personally used two virtualisation environments: Microsoft Virtual PC, which its version 2004 is free (as in beer) (2007 version is not) and I’ve been quite satisfiied with it: it’s a great virtualisation software, intuitive and easy of use, and the one I use in my workplace.

And the one I’ve just tested at home is InnoTek VirtualBox, Open Source and free (as in freedom). For me at least, the later is more important: I frankly don’t see myself capable of understanding, much less modifying, the source code of one of these things.

Right now I’m writing this entry from a virtual machine made with VirtualBox and running an Ubuntu Dapper Drake. No, I’m not going to the light side: it simply was the ISO file most at hand at the moment to test VirtualBox. In fact, my target for the next days is installing Vista. Long life the dark side! =)

So if you didn’t know virtualisation software, my advice to you is to give it a try: it’s simple to setup, intuitive to use and thanks to this technique we’ll have a safe environment to tinker with harmlessly.

Random Surname Generator

Fri 12 January, 2007

Aswering the challenge raised by Jon Galloway on his must-read blog, here’s is my solution to generate some random and fake surnames. Code has plenty of comments. Feel free, of course, to comment questions, criticism or even better, a cool refactor! =)

class Program
{
    
//An arraylist to contain ALL possible digrams (see below)
    
private static ArrayList AllDigrams = new ArrayList();
    
//An array list to contain ALL possible letters (see below)
    
private static ArrayList AllLetters = new ArrayList();
    
//A random seed for the main random generator
    
private static Random rSeed = new Random()
    
//A multidimensional array specifying the random "bones" of a surname. 
    // "A" is a vowel letter, "B" is a consonant letter
    //"AB is a vowel + consonant digram, and so on…
    //These combinations are made by hand, you could add or delete 
    //to fine-tune the kind of surnames you get
    
private static string[,] SurnameRandomTypes = new string[106]
            {
                {
"A",  "BA""B",  "A",  "BA"""},
                {
"B",  "A",  "BA""",   "",   ""},
                {
"A",  "BA""A",  "B",  "A",  "BB"},
                {
"A",  "B",  "B",  "A",  "BA"""},
                {
"A",  "BB""AB""A",  "",   ""},
                {
"BA""B""B",  "A",  "B",  "A"},
                {
"B",  "AB""A",  "BB""A",  "AB"},
                {
"B",  "AB""B",  "A",  "BB""AB"},
                {
"A",  "BB""A",  "B",  "AB"""},
                {
"AB""AA""B",  "A",  "B",  "A"},
            }
;

    /// <summary>
    /// 
    /// </summary>
    
static void Main()
    {
        
bool exit = false;
        
//We load ALL the possible digrams in memory, 
        //in the AllDigrams arraylist
        
LoadDigrams();
        
//Same for the possible letters, 
        //in the AllLetters arraylist
        
LoadLetters();
        do
        
{
            
for (int 0i <20i++)
            {
                Console.WriteLine(
"Random Surname:    {0}"
                    GenerateRandomSurname())
;
            
}
            Console.WriteLine(
"Press ENTER to generate another batch, X to quit");
            string 
sInput Console.ReadLine();
            if 
(sInput.ToString() == "x" || sInput.ToString() == "X")
                exit 
= true;
        
while (exit == false);
        
Console.ReadLine();
    
}

    /// <summary>
    /// This method generates a random surname and returns it.
    /// </summary>
    /// <returns></returns>
    
static string GenerateRandomSurname()
    {
        
string sRet "";
        
Random r;
        
//New random seed for the randomizer
        
= new Random(rSeed.Next(11000));
        
//and we get a random index for the 
        //SurnameRandomTypes multidimensional array
        
int rndIndex r.Next(09);
        
//Then we read the different "columns" of 
        //that "row" and decide if we need a vowel, 
        //a consonant, a vowel-consonant digram, 
        //or whatever
        
for (int 0i < 6i++)
        {
            
switch(SurnameRandomTypes[rndIndex, i])
            {
                
case "AA":
                    sRet +
getDigram(DigramType.TwoVowels);
                    break;
                case 
"AB":
                    sRet +
getDigram(DigramType.VowelAndConsonant);
                    break;
                case 
"BA":
                    sRet +
getDigram(DigramType.ConsonantAndVowel);
                    break;
                case 
"BB":
                    sRet +
getDigram(DigramType.TwoConsonants);
                    break;
                case 
"A":
                    sRet +
getLetter(LetterType.Vowel);
                    break;
                case 
"B":
                    sRet +
getLetter(LetterType.Consonant);
                    break;
                default
:
                    
break;
            
}
        }
        
//And we return the generated surname 
        //making the first letter upper case
        
return sRet.Substring(0,1).ToUpper() + 
            sRet.Substring(
1);
    
}

    #region Letters and Digrams
    
    
#region Structs and Enums
    
/// <summary>
    /// With this enum we’ll know what 
    /// the digram is made of
    /// </summary>
    
private enum DigramType
    {
        TwoVowels,
        VowelAndConsonant,
        ConsonantAndVowel,
        TwoConsonants
    }

    /// <summary>
    /// With this enum we’ll know is a letter
    /// is a vowel or not
    /// </summary>
    
private enum LetterType
    {
        Vowel,
        Consonant
    }

    /// <summary>
    /// A digram. With the actual digram ("th", for example)
    /// we store the range of frequency it appears on the 
    /// english language and its type
    /// </summary>
    
private struct Digram 
    {
        
public int iniRange;        //The beginning of its range
        
public int endRange;        //The end of its range
        
public string Value;        //Its actual content
        
public DigramType Type;     //Its type
    
}

    /// <summary>
    /// A letter. With the actual letter ("a", for example)
    /// we store the range of frequency it appears on the 
    /// english language and its type
    /// </summary>
    
private struct Letter
    {
        
public int iniRange;        //The beginning of its range
        
public int endRange;        //The end of its range
        
public string Value;        //Its actual content
        
public LetterType Type;     //Its type
    
}
    
#endregion

    /// <summary>
    /// This method returns the value 
    /// of a random digram of the specified type
    /// </summary>
    /// <param name="type">The type of digram the caller needs</param>
    /// <returns>The digram VALUE ("th", for example)</returns>
    
static string getDigram(DigramType type)
    {
        Random r 
= new Random(rSeed.Next(01000));
        
Digram nuDigram = new Digram();
        do
        
{
            
//We get a random number inside the TOTAL 
            //range of ALL the digrams
            
int freq r.Next(05548)//See LoadDigrams()
            
foreach (Digram digram in AllDigrams)
            {
                
//And if the random number is inside the 
                //current digram frequency range, 
                //we’ve got a winner!
                
if (freq >digram.iniRange && 
                    freq <
digram.endRange) 
                        nuDigram 
digram;
            
}
            
//But only if it’s of the type we need
        
while (nuDigram.Type !type);
        return 
nuDigram.Value;
    
}

    /// <summary>
    /// Gets a single letter VALUE of the specified type
    /// </summary>
    /// <param name="type">the type of Letter we need</param>
    /// <returns>the Letter VALUE</returns>
    
static string getLetter(LetterType type) 
    {
        Random r 
= new Random(rSeed.Next(01000));
        
Letter nuLetter = new Letter();
        do
        
{
            
//We get a random number inside the TOTAL 
            //range of ALL the letters
            
int freq r.Next(010025)//See LoadLetters()
            
foreach (Letter letter in AllLetters)
            {
                
//And if the random number 
                //is inside the current digram 
                //frequency range, we’ve got a winner!
                
if (freq >letter.iniRange && 
                    freq <
letter.endRange)
                        nuLetter 
letter;
            
}
            
//But only if it’s of the type we need  
        
while (nuLetter.Type !type);
        return 
nuLetter.Value;
    
}

    /// <summary>
    /// Simple boolean check to see if a given single letter is
    /// a vowel or a consonant
    /// </summary>
    /// <param name="checkLetter">The letter to check</param>
    /// <returns>True if vowel, false if else</returns>
    
static bool IsAVowel(string checkLetter)
    {
        
switch(checkLetter.ToLower())
        {
            
case "a":
            
case "e":
            
case "i":
            
case "o":
            
case "u":
                
return true;
            default
:
                
return false;
        
}
    }

    /// <summary>
    /// Thanks to the University of Bristol Department of Computer Science
    /// (and Google) I’ve managed to get a list of all the letters in the 
    /// english alphabet and their frequency of use in the English language
    /// Since Random deals with integers, I’ve multiplied all these values * 100
    /// The sum of all of them should be 10,000, which when calculating the 
    /// range of random numbers to draw should be 10,000 + the number of possible 
    /// letters; because the first letter range is from 0 to 1231, and the next 
    /// letter range begins en 1232 (prior end range +1)
    /// In the case of single letters this is correct, and the ranges are from 
    /// 0 to 10,025. 
    /// 
    /// But, I don’t know WHY, in the case of digrams the range goes 
    /// from 0 to 5,548. The frequency percentage of all the avaliable digrams,
    /// each of them multiplied by 100 and all of them added is NOT 10,000 as it 
    /// should be. Anyone knows why?
    /// </summary>
    
static void LoadLetters()
    {
        
// http://www.cs.bris.ac.uk/Teaching/Resources/COMS30124/Labs/freq.html
        // Percentage Frequency of Single Letters
        //
        //  E 12.31      L 4.03     B 1.62
        //  T  9.59      D 3.65     G 1.61
        //  A  8.05      C 3.20     V 0.93
        //  O  7.94      U 3.10     K 0.52
        //  N  7.19      P 2.29     Q 0.20
        //  I  7.18      F 2.28     X 0.20
        //  S  6.59      M 2.25     J 0.10
        //  R  6.03      W 2.03     Z 0.09
        //  H  5.14      Y 1.88      

        string[] _letterValue 
        
{
            
"e""l""b""t""d""g""a""c""v",
            
"o""u""k""n""p""q""i""f""x",
            
"s""m""j""r""w""z""h""y"
        
};
        int
[] _letterFreq 
        
{
            
123140316295936516180532093
            
794310527192292071822820,
            
659225106032039514188
        
};
        int 
lastEndRange 0;
        
//Examining those hard-coded arrays we fill 
        //the AllLetters collection of letter objects, 
        //assigning each one its range, value and LetterType
        
for (int 0i < _letterFreq.Lengthi++)
        {
            Letter nuLetter 
= new Letter();
            
nuLetter.iniRange lastEndRange;
            
nuLetter.endRange lastEndRange + _letterFreq[i];
            
lastEndRange nuLetter.endRange + 1;
            
nuLetter.Value _letterValue[i];
            
nuLetter.Type IsAVowel(_letterValue[i]) ? 
                LetterType.Vowel : LetterType.Consonant
;
            
AllLetters.Add(nuLetter);
        
}
    }
     
    
/// <summary>
    /// See LoadLetters comment
    /// </summary>
    
static void LoadDigrams()
    {
        
// http://www.cs.bris.ac.uk/Teaching/Resources/COMS30124/Labs/freq.html
        //
        //  TH  3.15   TO  1.11   SA  0.75   MA  0.56 
        //  HE  2.51   NT  1.10   HI  0.72   TA  0.56
        //  AN  1.72   ED  1.07   LE  0.72   CE  0.55
        //  IN  1.69   IS  1.06   SO  0.71   IC  0.55
        //  ER  1.54   AR  1.01   AS  0.67   LL  0.55
        //  RE  1.48   OU  0.96   NO  0.65   NA  0.54
        //  ES  1.45   TE  0.94   NE  0.64   RO  0.54
        //  ON  1.45   OF  0.94   EC  0.64   OT  0.53
        //  EA  1.31   IT  0.88   IO  0.63   TT  0.53
        //  TI  1.28   HA  0.84   RT  0.63   VE  0.53
        //  AT  1.24   SE  0.84   CO  0.59   NS  0.51
        //  ST  1.21   ET  0.80   BE  0.58   UR  0.49
        //  EN  1.20   AL  0.77   DI  0.57   ME  0.48
        //  ND  1.18   RI  0.77   LI  0.57   WH  0.48
        //  OR  1.13   NG  0.75   RA  0.57   LY  0.47 

        string[] _digramValue 
        
{   
            
"th""to""sa""ma""he""nt""hi""ta",
            
"an""ed""le""ce""in""is""so""ic",
            
"er""ar""as""ll""re""ou""no""na",
            
"es""te""ne""ro""on""of""ec""ot",
            
"ea""it""io""tt""ti""ha""rt""ve",
            
"at""se""co""ns""st""et""be""ur",
            
"en""al""di""me""nd""ri""li""wh",
            
"or""ng""ra""ly"
        
};
        int
[] _digramFreq 
        
{
            
31511175562511107256,
            
17210772551691067155
            
1541016755148966554
            
145946454145946453
            
131886353128846353
            
124845951121805849
            
120775748118775748
            
113755747
        
};
        int 
lastEndRange 0;
        
//Examining those hard-coded arrays 
        //we fill the AllDigrams collection
        //of Digram objects, assigning each 
        //one its range, value and DigramType
        
for (int 0i < _digramFreq.Lengthi++)
        {
            Digram nuDigram 
= new Digram();
            
nuDigram.iniRange lastEndRange;
            
nuDigram.endRange lastEndRange + 
                _digramFreq[i]
;
            
lastEndRange nuDigram.endRange + 1;
            
nuDigram.Value _digramValue[i];
            if 
(IsAVowel(_digramValue[i].Substring(01)) && 
                IsAVowel(_digramValue[i].Substring(
11)))
                    nuDigram.Type 
DigramType.TwoVowels;
            else if 
(!IsAVowel(_digramValue[i].Substring(01)) && 
                IsAVowel(_digramValue[i].Substring(
11)))
                    nuDigram.Type 
DigramType.ConsonantAndVowel;
            else if 
(IsAVowel(_digramValue[i].Substring(01)) && 
                !IsAVowel(_digramValue[i].Substring(
11)))
                    nuDigram.Type 
DigramType.VowelAndConsonant;
            else 
nuDigram.Type DigramType.TwoConsonants;
            
AllDigrams.Add(nuDigram);
        
}
    }
#endregion
}


Colorized by: CarlosAg.CodeColorizer

And here’s an example of the surnames it makes:

  • Andaso
  • Estecon
  • Ovloso
  • Eleasawh
  • Athene
  • Tertore
  • Setolyiis
  • Face
  • Lirsuco
  • Rofsender

kick it on DotNetKicks.com

Compressing and uncompressing ZIP files

Thu 4 January, 2007

For compressing and uncompresing files in ZIP format we have a very valuable tool at our disposal: the SharpZipLib library, made by IC#Code, the same developer group that brought us the awesome Open Source IDE for C# SharpDevelop, which I’ve mentioned before.

First thing we’ve got to do, then, is to download said library to our system. Once donde that, we must include it as a reference on the project we’re using it; and if we believe we’re going to use it somewhat frequently, the comfy option is to install it to the GAC. To do so, let’s open the Visual Studio 2005 Command prompt, located under Tools in the Visual Studio 2005 start menu group. When clicking on it, it opens a new console window and inside it we should go to the folder where we’ve downloaded ICSharpCode.SharpZipLib.dll (for easiness, I have it on a folder of its own at C:\Program Files) and once there we enter the following command:

gacutil /i ICSharpCode.SharpZipLib.dll

Thus we add the library to .NET’s global assembly cache.

So, either if we add the library to the GAC or not, we have to reference it in our project. For it, you know, once our project is created (be it a Console, Windows Forms or Web Forms) whe choose the Project, Add Reference menu item, and we choose the library on the dialog window that opens: on the .NET tab if the library is included in the GAC or we can search it with the tab Browse. Once the reference is included, we add the line


using ICSharpCode.SharpZipLib.Zip;

in our code and we are set to go.
One last disclaimer before gettint to it: to simplify this article I’ve decided for the code examples included to work in the Console and I’ve taken for granted some things like paths and file names. If you want this code to work don’t simply copy and paste it, you’ve got to adapt it to your system and your files.

Listing File Content

Let’s see first how can we list the contents of a ZIP file. for it, we simply declare an object called zip from the class ZipFile. See how SharpZipLib makes a ZipFile composed of ZipEntry objects, not of files or lines or any other thing. The ZipEntry class is going to be any of the entities that can be contained on a ZIP file, files or directories. Once knowing this, we can work our way through the entries on the ZIP file with a foreach loop and we simply show the name of the entry on the Console:

private static void ListZipContent(string sFile) 
{
    ZipFile zip 
= new ZipFile(File.OpenRead(sFile));
    foreach
(ZipEntry entry in zip) 
    {
        Console.WriteLine(entry.Name)
;
    
}

Colorized by: CarlosAg.CodeColorizer

Uncompressing Files

The plot thickens. To uncompress a ZIP file we open it as a ZipInputStream object, we navigate through its entries with the GetNextEntry() method and we save the binary content of each entry on a byte array. Said array will feed a StreamWriter object, which we’ll use to create the new file, which will be an exact uncompressed copy of the binary data stored on the ZIP file’s entry.

private static void UncompressZip(string sFile)
{
    ZipInputStream zipIn 
= new ZipInputStream(File.OpenRead(sFile));
    
ZipEntry entry;
    while 
((entry zipIn.GetNextEntry()) != null)
    {
        FileStream streamWriter 
File.Create(@"C:\Temp\" + entry.Name);
        long 
size entry.Size;
        byte
[] data = new byte[size];
        while 
(true)
        {
            size 
zipIn.Read(data, 0, data.Length);
            if 
(size > 0) streamWriter.Write(data, 0, (int) size);
            else break;
        
}
        streamWriter.Close()
;
    
}
    Console.WriteLine(
"Done!!");

Colorized by: CarlosAg.CodeColorizer

Compressing Files

For compressing files wer’ll use an object similar to the previous one but of the opposite purpose, ZipOutputStream. Wanting to keep this example simple, I’ve supposed we want to compress every existing file on the path passed as parameter sPath. Thus we’ll read all the files sitting on that folder, we’ll create a new ZipEntry object, get some information about the file with FileInfo (we could also use some CRC checking, but I wanted to keep this simple) to assign that information to the new entry, and add the entry to the ZipOutputStream object with its PutNextEntry method. Pay attention, this would create an empty entry: to really enter the data contained in the file we need to read its binary data with a FileStream as in the previous example and then call the method Write from ZipOutputStream to save those binary data on the most recent entry of the output Zip stream. Once read and included all the files, we finish and close the ZipOutputStream object.

private static void CompressZip(string sPath) 
{
    ZipOutputStream zipOut  
= new ZipOutputStream(File.Create(@"C:\Temp\test.zip"));
    foreach
(string fName in Directory.GetFiles(sPath))
    {
        FileInfo fi  
= new FileInfo(fName);
        
ZipEntry entry = new ZipEntry(fi.Name);
        
FileStream sReader File.OpenRead(fName);
        byte
[] buff = new byte[Convert.ToInt32(sReader.Length)];
        
sReader.Read(buff, 0, (int) sReader.Length);
        
entry.DateTime fi.LastWriteTime;
        
entry.Size sReader.Length;
        
sReader.Close();
        
zipOut.PutNextEntry(entry);
        
zipOut.Write(buff, 0, buff.Length);
    
}
    zipOut.Finish()
;
    
zipOut.Close();
    
Console.WriteLine("Done!!");

Colorized by: CarlosAg.CodeColorizer

And this ends this little introduction to SharpZipLib. IC#Code keeps an superb forum on which you can find some more code examples and a lot of answered questions.

Update 5/01/2007.- Playing a little bit with the library and VS 2005’s Object Browser, I stumble upon a class called FastZip. Hmmmmm. Yeah, it’s what it seems: a wrapper class to ease the process of compressing and uncompressing files with SharpZipLib. For example, to uncompress a file it would be as simple as this:

ExtractZip method’s three parameters are strings; and they stand for the name of the ZIP file to uncompress, the destination path for the uncompressed files and a mask for the type of files we want to extract. Warning: you can’t use an DOS mask such as "*.txt", you must use a regular expression. If we want to uncompress every file existing on the path, we should simply leave this last argument as null or empty string "".

private static void FastZipUncompress(string sFile)
{
    FastZip fZip 
= new FastZip();
    
fZip.ExtractZip(sFile, @"C:\Temp""");

Colorized by: CarlosAg.CodeColorizer

And to compress:

private static void FastZipCompress()
{
    FastZip fZip 
= new FastZip();
    
fZip.CreateZip(@"C:\Temp\walls.zip"@"C:\Wallpapers"false".jpg$");
    
Console.WriteLine("Done!!");

Colorized by: CarlosAg.CodeColorizer

In this example the method CreateZip accepts four arguments: the name and path of the ZIP file to be created, the folder where the files we want to compress are, a boolean parameter for stating if we want to make a recursive compression (to include possible subfolders), and last an string parameter specifying the mask we want to use for choosing the files we want to compress, in this example every JPG file. The same rules in using masks applies.

kick it on DotNetKicks.com

Codecruncher the Grey

Wed 15 November, 2006

Every morning it’s the same. I enter my firm’s building and I see a bunch of people waiting to be interviewed for a job. And I always have to restrain myself not to enter the room all crazy eyed and yell at them: “Fly, you fools!”.

I wonder why is this.

powered by performancing firefox

Fair justice

Tue 14 November, 2006

Good news for all of us, here, among other places. Some Dave Mitchell, a freelance English programmer and sysadmin, who bought a Dell laptop, has managed to get back the money that Dell charged him for the bundled O.S., a Windows XP Home I guess. Mitchell asked for his money (45 GBP) back arguing that he never used and never was going to use that Windows license, and invoking Microsoft’s own EULA for it.

Good for him. That’s something we all should do, Linux users or not. For example, my own HP Pavilion W5080 (I can’t link it, because after less than two years is already out of HP catalog) comes with a bundled Windows XP Home, that I was never going to use. No setup CDs, no manuals, everything stored on a recovery partition on the main hard disk. If you install any other O.S., even from the same family, you’re screwed (spanish link, sorry), you just made your warrant void. Even if your problem has nothing to do with the O.S.

I heartily dislike this solution because:

  1. I don’t see the reason why I have to pay for an O.S. I’m not gonna use. Moreover, if the O.S. I’m going to use is not free; I have to pay twice for the same concept.
  2. The computer’s manufacturar has no right to tell me how I must setup my hard disk.
  3. Usually the recovery partition is bigger than needed. Because of their saving on buying complete Windows licenses, I lose hard disk space.

Let’s hope this catches and more people decides to ask for their money back for an O.S. they’r enot going to use. And it shouldn’t be necessary: manufacturers should realize this and give the customer the choice of preinstalled O.S., if any.

powered by performancing firefox

Nine things developers want more than money

Thu 9 November, 2006

In the spanish main version of this blog I’ve just translated and published an original Rob Walling post, Nine things developers want more than money. It’s a great article, and since this is in English I’ll merely link to it here. My thoughts about it, coming up.

XNA development

Fri 1 September, 2006

Although everyone and his brother has already posted this, I gotta try…

Microsoft has made avaliable the beta of XNA Game Studio Express, a set of free tools for programming games targeted to Windows and XBox. It includes the XNA Framework, which is no less than a collection of managed libraries geared towards a (much needed) simplification of using DirectX.

Oriented to students and amateur programmers (and actually reaching out to almost every programmer1) at the moment XNA Game Studio is only compatible with Visual C# 2005 Express.

Tehre’s already a site (that I know of) collecting all the download links for all the needed tools (and yeah, they’re all free); and some tutorials to boot: XNA Development.

I don’t know why, but I don’t think I’m going to get out much this weekend…


1.- C’mon, which one of you has not once dreamed about game programming? It’s the Top Gun of computer programming!

SubSonic

Wed 30 August, 2006

Wow. I’ve just hurt myself: I’ve just seen Rob Conery’s webcast about the little library he’s created for .NET 2.0 and myu jaw has opened so much all by itself, and not precisely yawning, that it has crashed against my desk.

As Conery himself says, he’s followed Ruby on Rails for creating SubSonic (previously known as Action Pack). SubSonic is a Zero Code DAL, or Data Access Layer. Just like in Ruby, complete with scaffolding.

Beware, SubSonic is not a .NET implementation of Ruby On Rails. That’s MonoRail. It’s not even an adaptation, because RoR is a complete framework with Modell-View-Controller , data access layer and all the works. SubSonic is just an amazing data access layer.

I haven’t got the time (yet) to play a little with it, but if you’d like to stop feeling envy while watching Rails webcasts or presentations, take a look at the Introduction to SubSonic webcast.

Beware you jaws.

Update.- I forgot to link this excellent introduction by Jon Galloway. I’m of the same opinion: Microsoft should hire Conery and include the ActionPack.dll as part of Atlas. Or for giving SubSonic MVC capabilities. Or doing something with this stuff.

Google Code Hosting

Mon 31 July, 2006

Or how Google made its very own SourceForge.

Google has made avaliable for all of us with a GMail account, Google Code Hosting, a repository for Open Source projects hosted by Google. It uses Subversion, and allows the project administrators to manage a bug tracker, the project collaborators, add links to external webpages about the project, and so on.

I’ll keep telling you things as I keep trying it.