Sunday, September 20, 2009

Home Computer Setup

Recently entropy caught up with the Home Computer, and resulted in a reformatting and a replacement of the old 32 bit operating system with a new 64 bit operating system.
The strategy has changed to use virtual machines for specific purposes instead of installing everything on the physical machine.
So, now, this is the setup:

  • Physical machine: 64 bit laptop with 64 bit operating system, with:

    • 7-zip

    • AVG Anti Virus

    • Emacs

    • Google Chrome

    • MiKTeX

    • Mozilla Thunderbird

    • TortoiseSVN

    • VisualSVN Server

    • WinDirStat



  • Virtual machine for development, with:

    • AnkhSVN

    • Firefox

    • FxCop

    • NUnit

    • SqlServer

    • TortoiseSVN

    • Visual Studio



  • Virtual machine for tests and games.


Is it better? No.
Is it smarter? No.
Is it new? Yes, for me it is!

Thursday, July 9, 2009

History Based Estimation

Recently I started on a new programming project in my spare time. I call it History Based Estimation. It features a website to handle recording the elapsed time for tasks and using that to estimate future completion dates.

It is inspired by Joel Spolsky's Evidence Based Scheduling, which I've wanted to use since I read about it more than a year ago.

On my job we started using BugTracker.NET half a year ago, but that doesn't fill my need for the scheduling/estimating part. I started to write a web site in ASP.NET (web forms) three weeks ago, and open sourced it on SourceForge.net when I had something that looked like a start.

Features of History Based Estimation are currently:

  • Recording of projects, issues and tasks.

  • Prioritizing issues.

  • Recording estimates and time spent on tasks.

  • Chart with probability of completion dates.

  • Analysis of statistical average remaining time per issue.

  • Download of analysis in Word, Excel, and Latex formats.

  • Choice between English or Danish user interface.

  • Chart with historical task statistics (estimated time versus elapsed time).

  • Tracking of 'days off' when the person will be on holiday etc.



I think it is lacking in, at least, the following: There is no notion of person in the system. I.e. although it is possible for more than one person to use it, there is no authentication required and thus the system does not know who does what, who estimates what, and who has spent the time recorded.

Therefore, I hope to get more time to implement these features:

  • More than one person: I.e. record who is working on what and extract estimates per person.

  • Authentication linked to persons.



A technical note:


  • the web site is written in ASP.NET Web Forms

  • the business logic is written in C#

  • data is stored in a SQL Server database



As mentioned, the code is open source:

so if you would like to take a look at it, please follow the links. If you would like to give me feedback, or maybe even work on the code, please contact me.

Saturday, April 11, 2009

Article about parameter passing in c#

I found this article about parameter passing:
Parameter passing in C#

Friday, March 6, 2009

Cafés / restaurants with vegetarian dishes in central Denmark

We visited Grenå (on the tip of the nose of Denmark) this week. We were pleasantly surprised to find a café there called ØkoCafeen (ecological café) with a vegan burger on the menu card.

How many places do you find that in Denmark? (We know restaurant Pihlkjær in Århus with an ecological/vegetarian menu.)

In ØkoCafeen they sell ecological food, do wellness, and also have a small catalog of music and movies from Fønix Musik. I noticed a movie called Peaceful Warrior with Nick Nolte, which Eckhart Tolle recommends (according to the brochure).

They call the concept Living Nice, and have a web site here with info about the café and also a blog: Living Nice.

Saturday, January 10, 2009

Learning and Living

"To live is to learn."

"To read is to live."

Or maybe it is "Living is living" and "I am".

The last three months have meant some changes to how I work:

I now use source control for code related work: Subversion with TortoiseSVN in Windows Explorer and ankhsvn in Visual Studio. This has given me a feeling of greater security that my work is properly backed up, more speed in development since I don't have to manage (copy) revisions manually. Any new experiment I do can only destroy the changes I've made since the last time I committed changes to source control. Therefore I commit changes every time a piece of a task is completed. In addition to the code change itself, to each commit I add a short description of what has changed. This means that I get an overview of what has changed on a given project by reading the repository log.

Joel Spolsky says, among other things, that Daily Builds Are Your Friend. By setting up a build server I now have a system that, for most of the projects, will compile the code and test it. By using CruiseControl.NET I automatically get feedback when commited code breaks a build.

An extra benefit from the above is that I have learned how to write build scripts using NAnt. So now, after making some small code change, I can run a bat file and the solution will be compiled and the installers packaged for the consultants or for grabbing via ftp from a remote server.

This week I set up BugTracker.NET which seems to fulfil our requirements about a system that we can use internally for tracking bugs, issues, and requests from customers. I appreciate the work of Corey Trager and other people who release their private work for public use.

So now I'm about half-way through The Joel Test, and I don't know where this will end...

Thursday, October 2, 2008

Image browser with ASP.NET Ajax

Introduction

I have written an image browser page with ASP.NET, using ASP.NET Ajax to retrieve information about images on the server. Images are displayed using a single aspx page and a folder with jpg files. The code-behind is written in C#. No database is involved.

Background


My goal was to show my family some photos on a web page and hopefully spending less than a few hours accomplishing that. So I wanted to do so without using a database, without titles, without descriptions, without tags, etc. However, I included the shooting date of the photo as part of the file name, since it provided a way to retain som information without using a database.

You see the resulting web page on the right.

The code

Code-behind (C#)

I first created a aspx web form, and in the code-behind wrote a static web method to return information about the images on the server:
[WebMethod]
public static Image[] GetImages()
{
// The virtual path to the image folder:
// (in this case a folder that contains some photos)
string imageFolderVirtualPath = "~/Photos/";
string imageFolderPath = HttpContext.Current.Server.MapPath(imageFolderVirtualPath);
List<image> images = new List<image>();
DirectoryInfo diImages = new DirectoryInfo(imageFolderPath);
// Only *.jpg files are included in this case:
foreach (FileInfo fiImage in diImages.GetFiles("*.jpg"))
{
string fileName = fiImage.Name;
// If the file name starts with the DateTime pattern yyyy-MM-dd,
// the date is parsed from that:
string date = string.Empty;
int year = 0;
int month = 0;
int day = 0;
if (fileName.Length > 9 && Int32.TryParse(fileName.Substring(0, 4), out year)
&& Int32.TryParse(fileName.Substring(5, 2), out month)
&& Int32.TryParse(fileName.Substring(8, 2), out day))
{
date = new DateTime(year, month, day).ToLongDateString();
}
images.Add(new Image
{
Date = date,
VirtualPath = CombineVirtualPaths(imageFolderVirtualPath, fileName)
});
}
return images.ToArray();
}

A helper method combines the virtual paths:
private static string CombineVirtualPaths(string virtualPath1, string virtualPath2)
{
return string.Format("{0}/{1}", virtualPath1.Trim('~', '/'), virtualPath2.Trim('/'));
}

A helper class contains information about an image:
public class Image
{
/// <summary>
/// The virtual path to the image file
/// </summary>
public string VirtualPath { get; set; }

/// <summary>
/// The date as a string
/// </summary>
public string Date { get; set; }
}


html/aspx markup

In the *.aspx file I have the following markup:
<body onload="GetImages();">
<form id="form1" runat="server">
<asp:ScriptManager id="sm1" runat="server" EnablePageMethods="true" EnableScriptGlobalization="true">
</asp:ScriptManager>
<div>
<div id="divButtons" style="float: left;">
</div>
<div id="divImage" style="float: left;">
</div>
</div>
</form>
</body>


Javascript

On load fires a javascript method that retrieves info from the page method:
// Information about the Images:
var images;

// The index of the currently shown Image:
var currentImageIndex = 0;

// Calls the page method to obtain information about the Images:
function GetImages() {
PageMethods.GetImages(GetImagesCompleted);
}

// The call-back where information about the images is returned:
function GetImagesCompleted(result) {
images = result;
ShowImage();
}

// Shows the Image:
function ShowImage() {
var currentImage = images[currentImageIndex];
var date = currentImage.Date;
var imgImage = "<img id='imgImage' alt='" + date +
"' title='" + date + "' src='" + currentImage.VirtualPath "' />";
var dp = document.getElementById("divImage");
dp.innerHTML = imgImage;
document.title = date;
ShowButtons();
}

A separate javascript method displays navigation buttons as appropriate:
// Shows the buttons:
function ShowButtons() {
// Gets localized texts (English or Danish) for the buttons.
// This only works with the following two settings:
// - The ScriptManager on this page must have: EnableScriptGlobalization="true"
// - web.config must have: <globalization culture="auto"> (in <system.web> section)
// The default English texts:
var first = "First";
var previous = "Previous";
var next = "Next";
var last = "Last";
if (Sys.CultureInfo.CurrentCulture.name.toLowerCase().startsWith("da")) {
// The Danish texts:
first = "Første";
previous = "Forrige";
next = "Næste";
last = "Sidste";
}
var button1 = "<div><input type='button' style='width: 75px;'";
var btnFirst = button1 + " value='" + first + "' onclick='ShowFirstImage();'";
var btnPrevious = button1 + " value='" + previous + "' onclick='ShowPreviousImage();'";
var btnNext = button1 + " value='" + next + "' onclick='ShowNextImage();'";
var btnLast = button1 + " value='" + last + "' onclick='ShowLastImage();'";
if (currentImageIndex == 0) {
btnFirst += " disabled='disabled'";
btnPrevious += " disabled='disabled'";
}
if (currentImageIndex == images.length - 1) {
btnNext += " disabled='disabled'";
btnLast += " disabled='disabled'";
}
var button2 = " /></div>";
btnFirst += button2;
btnPrevious += button2;
btnNext += button2;
btnLast += button2;
var db1 = document.getElementById("divButtons");
db1.innerHTML = btnFirst + btnPrevious + btnNext + btnLast;
}

// Shows the first Image:
function ShowFirstImage() {
currentImageIndex = 0;
ShowImage();
}

// Shows the previous Image:
function ShowPreviousImage() {
if (currentImageIndex > 0) {
currentImageIndex -= 1;
ShowImage();
}
}

// Shows the next Image:
function ShowNextImage() {
if (currentImageIndex < images.length - 1) {
currentImageIndex += 1;
ShowImage();
}
}

// Shows the last image:
function ShowLastImage() {
currentImageIndex = images.length - 1;
ShowImage();
}


Points to notice

  • A useful application built in a single web form and a folder with images

  • The EnableScriptGlobalization feature on the ScriptManager and the ability to extract language information in javascript using Sys.CultureInfo.CurrentCulture.name.



License

Copyright (c) 2008, Ole L. Sørensen
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
  • Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  • The names of its contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

(The above license is based on the BSD license here: http://www.opensource.org/licenses/bsd-license.php)

Wednesday, October 1, 2008

Thinkpad X61S recovery

The laptop that I use at work, an IBM Lenovo Thinkpad X61S, has suffered a case of brain loop while installing Service Pack 1 of Visual Studio 2008 / .NET 3.5. This means, that I cannot start the computer in Windows Vista. I am now doing the following to recover Windows Vista as well as recover data:
  1. During boot, pressing F8 opened an overview of boot methods, e.g. "safe mode".
  2. I chose the first option: "Repair Your Computer".
  3. I logged in to Rescue and Recovery with an administrator account.
  4. I opened a command prompt.
  5. I connected a USB hard disk.
  6. I copied data from the C-drive to the USB drive.
  7. I recovered the system to its initial state (as when it was delivered).
  8. After that I am going to install programs etc. (e.g. VS2008/.NET 3.5 SP 1 before I work on the computer!!!!).
  9. Finally I will copy data from the USB drive.