Archive for the ‘Geeky’ Category.

K&R – Solution to Exercise 1.23

I’m working my way through The C Programming Language at the moment, and so far I’m loving C’s purity and leanness.

One of my few disappointments with the book is the lack of solutions to the exercises. The exercises are refreshingly challenging because the book isn’t aimed at beginning programmers. Unfortunately this means that the desire to validate one’s solutions is quite strong. Fortunately, Google had a solution to this problem: Richard Heathfield’s solutions site.

I just finished my solution to exercise 1.23 (“Remove all comments from a C program”) and I’m quite chuffed with it so thought I would share it here. Out of the multiple solutions provided on Richard’s site, mine was about the closest to following the guidelines as far as what knowledge one is supposed to have of C by that (early) point in the book (the only thing I cheated with is the use of break and continue – it would have just been quite ugly without those two small additions). Basically the solution is a state machine using if / else instead of more traditional switch methods as switch had not yet been introduced.

My solution deals with all the special cases I could think of, and even deals with the tricky sample input on Richard’s site, provided at the bottom of the solutions page for this exercise.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
/*
 * K&R Exercise 1-23
 *
 * "Write a program to remove all comments from a C program. Don't
 *  forget to handle quoted strings and character constants properly.
 *  C comments don't nest."
 *
 */
 
#include <stdio.h>
 
int main()
{
    int c;
    int c2;
    int in_quotes = 0;
    int in_comment = 0;
    int current_quote;
 
    c = getchar();
    while (c != EOF)
    {
        if (!in_comment && !in_quotes)
        {
            if (c == '\'' || c == '"')
            {
                in_quotes = 1;
                current_quote = c;
                putchar(c);
            }
            else if (c == '/')
            {
                c2 = getchar();
                if (c2 != EOF && c2 == '*')
                {
                    in_comment = 1;
                }
                else
                {
                    putchar(c); /* Just a regular '/', so output it. */
                    c = c2;
                    continue;
                }
            }
            else
            {
                putchar(c);
            }
        }
        else if (in_comment)
        {
            /* Check for a closing comment. */
            if (c == '*')
            {
                c2 = getchar();
                if (c2 != EOF && c2 == '/')
                {
                    in_comment = 0;
                }
                else
                {
                    /* Don't advance to next character in stream. */
                    c = c2;
                    continue;
                }
            }
        }
        else if (in_quotes)
        {
            /* Skip over escaped chars. */
            if (c == '\\')
            {
                putchar(c);
                c = getchar();
            }
            else
            {
                /* Check for closing quote. */
                if (c == current_quote)
                    in_quotes = 0;
            }
            putchar(c);
        }
 
        c = getchar();
    }
 
    return 0;
}

Users Are Not Stupid

Really!  And, quite frankly, I’m sick and tired of programmers talking about them like this (not all programmers, some are worse than others, and all the usual disclaimery stuff applies)

I’m a user first, programmer second.  So are you.  Chances are you were using a computer for everyday tasks for a while before you started programming.  The fact is, we will never again be able to see computers in the same way as we did back then.  This is why we have average users test our software, and it’s vital that we do so.

Think about what it means to be a programmer.  Our job is to make computers more accessible to our dear users.  Everything we do, we ultimately do for them.  If we code with the user in mind at all times, and respect their needs, then everybody will ultimately be better off.

Sure, sometimes (hell, often!) a user’s request may not feel like the right thing for the system, and sometimes it won’t feel like the most elegant thing to do, but there are times when a leap of faith is required.  There will always be a balance between what users want and what we feel is good for them, but I’m appealing to you to lean in the direction of the user.

Nobody likes validating input to death, or putting up what seems like endless tooltips and hints all over the place, but users really do appreciate the little things we do to make their experience better.  Unfortunately, it’s more of a case of preventing outrage than garnering actual praise, but that’s what we signed up for, for better or worse.  The more people use the system for its intended purpose and the less we hear back, the better.

Make your error messages friendly.  Let the user feel like they have a more casual relationship with the system and they might feel less frustrated when something goes wrong.

“Don’t you worry about blank, let me worry about blank.”

Customer service rules apply even when the customer isn’t right in front of us.  Think of the system as an extension of yourself.  Build a little bit of your personality into the system for a more personal experience.

Please, please don’t think of your users as < than you, it’s just not fair.  Think of how out of place you would feel in their profession.  Respect the average user, and let’s make the computer experience better.  For them.

Tubecaster 3 UI Mockup

Here’s a mockup of the main window for the upcoming Tubecaster 3.  The release will include support for multiple downloads at once, playlist download support and built-in media conversion tools.  Stay tuned!

Tubecaster 3 main window

Pre-populate Django ModelForm with Specific Queryset

I just had a situation where I was trying to filter the queryset for a ModelMultipleChoiceField based on the currently logged-on user.  I was going crazy trawling through the Django docs and eventually Google.  It seemed like something which should be so simple, but there was no obvious way to do it.  Eventually I found the answer, and it IS simple!  As an example, let’s say you have the following two models as part of a simple photo gallery app:

?View Code PYTHON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Photo(Model):
    name = CharField(max_length=100)
    caption = CharField(max_length = 150)
    user = ForeignKey(User)
    upload_timestamp = DateTimeField(auto_now_add=True)
    image = ImageField(upload_to="user_images/%Y/%m/%d/")
    thumbnail = ImageField(upload_to="user_images/%Y/%m/%d")
    def __unicode__(self):
        return self.name
 
class Album(Model):
    name = CharField(max_length=100)
    caption = CharField(max_length = 150)
    user = ForeignKey(User)
    photos = ManyToManyField(Photo, related_name="albums", blank=True)
    creation_timestamp = DateTimeField(auto_now_add=True)
    cover_photo = ForeignKey(Photo, related_name="cover_photos")
    def __unicode__(self):
        return self.name

We then define a ModelForm based on the Album model, which allows users to create albums with photos they’ve previously uploaded (pretend we’ve already made that possible). We only expose the “name”, “caption” and “photos” fields because we’ll fill in the others automatically as part of our view:

?View Code PYTHON
1
2
3
4
class AlbumCreationForm(ModelForm):
    class Meta:
        model = Album
        fields = ("name", "caption", "photos")

Now here’s the real magic. Ordinarily, when first showing the form (pre-POST) we would create it like this and pass it to the template:

?View Code PYTHON
form = AlbumCreationForm()

The problem here is that by default we’ll get all photo objects, i.e. the result of “Photo.objects.all()”. That’s a problem because in this case we just want to list the photos belonging to the current user. To do this, just add the following line:

?View Code PYTHON
form.fields["photos"].queryset = Photo.objects.filter(user=request.user)

It turns out that form fields can be accessed as a dictionary attached to the form instance, and that if the field is model-related, like “photos” in the example, you can update its queryset dynamically.

Here’s a partial view which uses the last two code samples, to provide some context:

?View Code PYTHON
1
2
3
4
5
6
7
8
9
10
11
12
13
def create_album(request):
    if request.method == "POST":
        # Process form.
    else:
        form = AlbumCreationForm()
        # Get just the photos belonging to this user.
        form.fields["photos"].queryset = Photo.objects.filter(user=request.user)
 
    template_vars = RequestContext(request, {
        "form": form,
        "user": request.user
    })
    return render_to_response("create_album.html", template_vars)

That’s it! Adding the one extra line to the view gives us the filtering we need.

Server Fault Private Beta

Following on from the wildly successful Stack Overflow programming questions and answers website, Jeff Atwood and Joel Spolsky have launched Server Fault, a questions and answers site following the same format but now for “system administrators and IT professionals” (currently in Private Beta, click here for sign-up instructions).

stackoverflow_logo

serverfault_logo

I’ve been using Stack Overflow for about 5 months and I absolutely love it. It has become the definitive, and I dare say de facto standard, questions and answers one-stop-shop for programmers. You can post a question for just about any programming topic and receive an answer within minutes, sometimes even seconds. This removes an old hassle with posting questions on Web 1.0-style forums where you had to wait impractically long lengths of time to receive answers.

These sites don’t just follow any standard Q&A format either.  Just take a look at the diagram on the about page of either site and you’ll see that they’re a deliciously freakish Wiki/Blog/Forum blend.

One of the things I love about boths sites is their innovative karma and badge system, where users are rewarded by the community for making valuable contributions.  This gives users a reputation score which appears next to their name wherever it appears on the site.  This can be used as an assessment of someone’s overall standing in the community.  Badges are awarded for special achievements like providing an especially highly-rated answer or for being recognised as an expert in a particular technology.

Of course possibly the most important feature of boths sites is that you don’t need to be logged in to ask or answer questions.  This removes yet another annoying hurdle for the casual help-seeker.

I encourage everyone in IT, be it programming or otherwise, to sign up to at least one of these – you won’t look back.

-Wayne