Monday 30 November 2009

Black eyed bean and squash stew

Oh dear, I really should have taken a photo of this, cos it was lovely. Anyway, this depends heavily on what I found at the Farmer's Market this week and two weeks ago. The insistence on small squashes is because that is what we have available this year. I'm told the weather was just too cold during April and May and they never really got going.
Note, the main ingredients are all in pretty vague amounts. That is fine, we are not baking, so little precision is needed. 

Ingredients

  1. 250g black-eyed beans, soaked overnight
  2. 2 small Kabocha squashes
  3. About 20 shallot-type onions
  4. Two or three cherry-bomb chillis
  5. Large handlful of rainbow chard
  6. Lots of garlic
  7. 2 bay leaves
  8. Twig of rosemary, twig or two of thyme
  9. 2 pints of vegetable stock
  10. Dessertspoon of molasses/treacle

Method

  • Get someone who is not terrified of pressure cookers to deal with the beans. Otherwise, I would treat them like kidney beans, hard boil for 10 minutes to make sure they are no longer poisonous, then simmer for an hour or so until soft and floury inside. Are black-eyed beans poisonous? Of course you can use tinned, and I often do. Advantages of dried are: you don't have to carry the water and the weight of the tins, plus the beans will soak up more flavour from the sauce if they are not aready cooked to death and swimming in tin-juice.
  • Get a large pan and start frying the whole, peeled shallots in oil. Do this very gently, for 20 mins to half an hour.
  • Meanwhile, cut the squashes into halves (they really were small!) and take out their seeds. Place cut-side down on an oven tray at around 190°C, also for half an hour or until soft.
  • When the onions are halfway there, add the herbs and four or five chopped up cloves of garlic. You don't want to burn the garlic, it tastes horrible.
  • When the onions are golden, pour in the stock. There really is no shame in using powdered stock, such as Marigold, especially if you are adding lots of other flavours.
  • Add in the molasses (this means, stick a dessertspoon in the tin, take it out full and leave the spoon in the pot of stew until the molasses has slid off it).
    Make a hole in the chillis with the point of a knife and add them whole. This worked very well with fresh juicy chillis and we got as much heat as seems reasonable with an autumn squash stew. By all means slice them up and add with the garlic if you prefer.
  • While this is all simmering, get the cooked squash out of the oven and turn the oven to 140°C.
  • It should be fairly easy to spoon the flesh from the skin and just drop spoonfulls and lumps into the stewpot. The cut flesh will be slilghtly carmelised, the skin will be a bit blackened and you don't need it.
  • Put the stewpot (mine is cast iron) in the oven for about 40 mins.
  • Just before serving, slice the chard across and fry gently in butter with garlic until wilted.
  • Serve the bowls of lovely orange stew with a topping of bright green chard and garlic. It is pretty filling!

In case you are wondering why I haven't blogged on anything techy in I don't know how long, the answer is MCTS. I am studying for Microsoft Certification as a Technical Specialist (Foundation). This is difficult and also pretty dry. I am producing no work of any creative value and you really don't want to know, trust me.

Tuesday 3 November 2009

Regexes from the perspective of a noob. Also autumn images.



Pictures this time are from a visit last week to Anglesey Abbey. I've no idea what the round-leaved shrub is called but it is lovely, isn't it?
The purple berries likewise. I did buy one of these a couple of years ago but it failed so comprehensively that I can't even remember where I planted it. The last photo is a Japanese Maple. But you knew that.

There comes a time, for any programmer, when they have to get their hands dirty with regular expressions. Yuk. They look like maths but are not really, as the rules are fairly random. This cannot be helped, as the system grew organically and is used by too many languages and too much legacy code to change.

One thing I dislike very much and will change in my own code is seeing a regex like this:

string matchString = @"^(?\\d{4}-\\d{2}-\\d{2})\\s*(?



What on earth does that mean? (Actually I had to break this line up so it is readable. In my code editor it is all on one line but of course that wraps and "pre" tags don't.) You look in tutorial books and on MSDN and other places and all the examples seem to be like this. Do you know, you are allowed to approach this like a normal programmer, not a machine, and break it all up into smaller chunks, each of which has a sensible name and a comment?


string dateMatch = @"(?\d{4}-\d{2}-\d{2})"; // 0000-00-00 pattern
string timeMatch = @"(?

Then add them all together:

string matchString = @"^" + dateMatch + @"\s*" + timeMatch + findExit + exitCodeMatch; 

Isn't that so much nicer? I for one certainly feel that regexes are slightly less likely to come back and haunt me later if I compose them in this way.But as I said in the title, I am still a noob in this area.


By the way, the @ signs are peculiar to .Net and mean yes, I do want  those backslashes. The code won't compile without them.

The more eagle-eyed of you may notice that this example comes from an exercise in the MCTS Microsoft .Net Framework - Application Development Foundation book. Don't worry, I composed the regexes myself and there may well have been a better way of doing it.

Wednesday 14 October 2009

Models, Views and Controllers

Pork Scratchings
Another nerdy post, I'm sorry. To make up for that, and because I was glued to every one of Jamie Oliver's adventures in the US, I have a gluttonous photo for you. I bought a bag of pigskin from the Farmers' Market on Saturday and made my very own Porky Scratchings from it. I used the recipe from Jamie's America, which involves stirring cayenne, cinnamon, seasalt, honey and garlic into the cooked scratchings and putting them back in the oven for 8 minutes. This was gorgeous but a little too much like Nigella Lawson's Union Square Café bar nuts from Nigella Bites (same topping but with brown sugar and rosemary). Next time I'll try just fennel, garlic and seasalt.

Well, for some time now, I've had the first chapter of a book on ASP.NET MVC on my desktop. It's about a site called NerdDinner. For some reason, I decided to actually take a look at it and started to work through the example. And I instantly fell in love! I've known I want to program in C# for several years now, and that I feel comfortable in Visual Studio. I am also aware that there are things called "Content Management Systems", lots of them, and only one of those written in .Net. What I wanted from a CMS would be a way of managing content (of course), so the customer can change what is on the page, keeping it up to date. I would therefore need a membership system. I am aware that it is important to keep data storage well away from the page itself, so that database tables and the classes that represent them can be looked after. The problem is that what we can now call the "traditional" ASP.NET structure, with code behind pages and databound gridviews is that it is easy to get into an almighty mess, which at some point needs to be sorted out. Then it looks like way too big a task.

I looked at various "Content Management Systems". Why are they called that anyway? Why not "Website Management Systems" or something else. Wordpress is supposed to be easy but I didn't get on with it, as it is pretty rigid. Fair enough, it was designed for blogging anyway. I investigated Drupal. Huge learning curve and writtten (like many CMSs) in PHP. No thanks. I looked at DotNetNuke. Two problems: it dumps a big load of mysterious files and language in your website, and seems to require a whole database all to itself. Third problem, I could in no way get this to work on my Vista PC with SQL Server, with or without IIS. Forget it. This was disappointing, as I really would prefer to stick with Visual Studio.

I tried Django late last spring, using various books and the help on the Django site. Python is a language that certainly appeals, it is clean, nerdy in a good way and does not carry all the bloat (written in various styles) that PHP does. To my frustration, I could not get beyond the most trivial examples. Neither could I work out where to keep my CSS, images and Javascript files. The writers of all these books seemed to regard the matter as unimportant. Examples were written with inline CSS (yuk!).

So, ASP.NET MVC. It doesn't call itself a "Content Management System", any more than .Net itself does. It's a Framework. That sounds much more open. As long as you have C# 3.0 (check) and some kind of MS SQL database (apparently Web Developer Express 2008 will do) you're in.

What appeals to me is that so many other modern buzzwords and ideas seem to be a part of this. They have copied ideas from Ruby on Rails (I had tried that as well and found it difficult, now I would be back in my comfort zone). It was based on the old-fashioned but newly discovered pattern "Model, View, Controller". This separates the pretty web pages from the content in the database and is all run with a set of "controllers". There is a huge emphasis on testability, even designing with behaviour and testability in  mind from the start. You are encouraged to import and use open-source test tools such as NUnit and Moq (I'm learning). The great JQuery library is part of the framework.

As for the parts I already know well, CSS can go anywhere the views can find it (typically in a "content" folder. Web pages are built up using a master page and come out with nice clean html. Any javascript or id attributes are what I put there myself and not generated out of monolithic .Net widgets.

Unless I want them of course. MVC is not the dark side of the .Net. You can (fairly) easily add in bits of web form-type ASP.Net when you want to.

I'm so happy, I'm getting  incoherent. Once I've worked through the superb Steven Sanderson book Pro ASP.NET Framework, I'm going right back to my portfolio and rewriting everything in MVC. It's light, it's programmer-like and I love it.

Wednesday 30 September 2009

How bread gets made in this house

My bread recipe is an adaptation of Mollie Katzen's in The Enchanted Broccoli Forest (I know that is twee but her later books have more grown-up titles). I have been making it pretty much ever since we left Germany (12 years ago) because I couldn't find any nice English bread. Things look better these days but I still like my own.

This recipe produces bread that is half wholemeal and half white. It has a good texture, provided by the nuts and grains and most people love it. I do NOT use a breadmaker, I think they are silly. I have 6 loaf tins, each for a roughly 750g loaf, and that fills my oven. I freeze 5 and we start eating the other one. I make two amounts of her recipe. I must mention, it has one "bug", in that she asks for 2 cups of water. This will never work with such a lot of flour! use 3.

cup = 250ml
tablespoon = 5ml


Ingredients
  • 3 cups warm water
  • 1 tablespoon dried yeast
  • pinch sugar or honey
  • 4 ½ cups strong wholemeal flour
  • 4 cups strong white flour
  • 1 cup cooked grains (barley, quinoa or millet for example)
  • ½ cup seeds (sunflower, linseed, pumpkin, sesame, poppy - poss. not all at once)
  • 1 tablespoon salt
  • ¼ cup oil
  • 1 dessertspoon honey or molasses

Method
  1. Cook ½ cup of grain (barley, millet or quinoa, for example) in 1 cups of water. You need to bring it to the boil and then cover up and simmer for 10 minutes. Then leave to cool until just hand-warm.
  2. Get a large mixing bowl and add 3 cups hand-warm water.
  3. Add the dried yeast and a pinch of sugar or honey.
  4. After about 5 mins you will see the yeast start to move around. At this point add 1½ cups of wholemeal flour and whisk it in. Leave for ½ hour or so until it has a foamy top. This stage is called the sponge and is important, as the yeast gets a chance to grow without lifting a lot of heavy flour.
  5. Now add a lot more stuff! Stick a dessertspoon in some honey or molasses and add to the mix.
  6. Now add the salt and the oil
  7. Stir in the cooked grains and the seeds
  8. Beat in three more cups of wholemeal flour
  9. Stir in two cups of white flour. this will be much harder
  10. Mix in the last two cups of white flour with your hands. After a while, the dough starts to come together. Sometimes you have to add more flour, sometimes it is hard to incorporate it all. Tip it onto your work surface and knead it until you have a nice smooth ball of dough
  11. Put it back into the bowl and leave to rise for at least two hours. More than four and it will reach its maximum size and collapse but this has never caused me any problem
  12. Oil three loaf tins
  13. Take out the dough and knead it again on a floured surface. Divide it up into three portions and press one down into each tin
  14. Leave to prove for about an hour (it really depends on the weather, yeast likes it warm)
  15. When the dough is starting to rise above the rim of the tin, turn the oven on to 190°c (fan oven)
  16. Put the bread in only when the oven has reached temperature (this is baking, not stew!) and bake for 45 minutes
  17. To test the bread, turn it out of the tin and tap the bottom. It should sound hollow
  18. You might want to give it at least 5 minutes so you don't burn your mouth on the first gorgeous slice with butter!
Variations
I always make two batches, as I said. A common combination is barley for the grains plus pumpkin and sesame seeds. I use molasses in this one. In the other bowl I would have quinoa or millet for the grains plus poppy and sunflower seeds. I would use honey in this mix.

Mollie Katzen also suggests chopped dried fruit. As a family of marmite addicts, this is not all that appealing, since we use this as our everyday bread. I have alos at times replaced most of the wholmeal flour with rye, or the white flour with spelt. Both of these work fine. The grains and seeds are also optional, bear in mind that leaving them out means you have less mass, so perhaps marginally smaller loaves.

I find the American habit of using cups to be well suited to measuring flour. I have tried putting all 8½ cups of flour for one batch on my scales and it just runs over. Far easier just to keep a clean cup measure and dip it into the flour bag. You could use an ordinary cup (not mug!) and work out roughly where 250ml would reach to. For a ¼ cup you could try an egg cup. This is only used for measuring oil, so it need not be accurate. Our egg cups have holes in the bottom for water to drain away, so I don't measure liquids with them!

I think I'll take pictures of the sponge and dough stages next time I bake, so you can see them.

Tuesday 29 September 2009

Many threads make light work



Today is the final episode in my threading story. Next time, I'll talk about bread, and possibly Wicken Fen as well. The image on the left is of my coffee cup in front of its cafetière. The strange felt object is a coffee cosy, kindly made by my sister. Bet you don't have one of those!

Previous episode

As I hinted before, the separation of incoming stream from the list of words created, nice though it is as far as Object Orientation is concerned, makes even more sense if you are building up words from several streams and adding them to the same wordlist. Like trying to find out how many times the word "thriller" came up just after Michael Jackson's death (I'm trying to think of a one-word example!).

So, this time we'll start with an array of readers. This one has three. I amended the assignReaderContent function to give each one two different paragraphs from The Star by Arthur C Clarke (the first 6, in fact). I then created a single WordList and a list of WordListBuilder and a list of Threads. All Threads (there will be three) must share the same WordList. The function setupBuilderList is passed all three lists plus the WordList object, and associates them all together:

    static void setupBuilderList(List<WordListBuilder> bList,ICharReader[] rArray, List<Thread>threadList, WordList wList)
    {
        for (int i = 0; i < rArray.Length; i++)
        {
            bList.Add(new WordListBuilder(rArray[i], wList));
            WordListBuilder.buildWordListStarterOp listStarter = bList[i].buildWordListStarter;
            threadList.Add(new Thread(new ParameterizedThreadStart(listStarter)));
        }
    }
There is a lot going on here, and quite a few new parts of ASP.NET and the classes I have created to explain. Of course, at this point there are no Threads or WordListBuilders, so we have to make one builder to enclose each reader and associate each with a thread. We create a new builder for each reader, as before, passing the reader and the wordlist to the constructor. Then we declare a delegate, called buildWordListStarterOp for the builder in question to communicate with the rest of the operation.The starter op. in question is a member function called buildWordListStarter, which has to be passed an object (as does the delegate):

        public void buildWordListStarter(object state)
        {
            if (state is BuildWordListParams)
            {
                BuildWordListParams oP = (BuildWordListParams)state;
                oP.myWordListBuilder.buildWordList();
            }
        }

        public delegate void buildWordListStarterOp(object state);

In the setup function, a ParameterizedThreadStart object is required, so we can give the thread something to work with. The parameter has to be of type system.object. the BuildWordListStarter member function expects to be handed an object of the class BuildWordListParams:

class BuildWordListParams
    {
        public WordListBuilder myWordListBuilder;
        public BuildWordListParams(WordListBuilder a)
        {
            myWordListBuilder = a;
        }
    }

Of course, since we are only passing a list, and a list is already a system.object, it is not necessary to go to the trouble of declaring BuildWordListParams. On the other hand, it is now there, and if I wanted to pass something else, for example and instruction to ignore common words such as "the" and "it", I can just add them to this declaration and it remains just one object.

This class simply passes on an object of type WordListBuilder. Assuming all goes well (and I confess, we don't have any exception handling here) this means you can take the BuildWordListParams object and just call its buildWordList member function, the same one we have been using all along.

In the static void function, this buildWordListStarterOp is called listStarter and is then passed to the new Thread in its constructor. It is perhaps not necessary to delve into the workings of threads in general. I take the view that the ASP.NET team write Thread libraries so I don't have to.

We have a list of builders and a list of thread. We now set up the timer with just the same function as last time.

The last static function (startThreads) is to start each thread off, giving it the correct parameter as it goes:

    static void startThreads(List<thread> tList, List<wordlistbuilder> bList)
    {
        int i = 0;
        foreach (Thread t in tList)
        {
            BuildWordListParams p = new BuildWordListParams(bList[i]);
            t.Start(p);
            i++;
        }
    }

Each Thread is passed the corresponding WordListBuilder.

One more, rather important, point. If you have three threads able to access a resource, such as a list of words at the same time, you may well end up with rubbish results. The content of both member functions of WordList, AddNewWord and makeReportCalledBack are enclosed in a lock statement. This ensures only one thread (we hope, containing a builder) will access it at any one time. It will then be released for another thread to use.

Here are some screenshots:

Here, you can see that the main thread is number 9, and that numbers 10-12 have been assigned to the different builders.

Here, the main thread has finished, all builders have been assigned their char readers and all threads have been started.


We are getting the first report from thread 6, which is the Timer/WordList.













At this point most or all of the content has been read. I counted up instances of the word "that" in my 6 paragraphs and there are, indeed 10.

Here, two of the threads have hit the EndOfStreamException  and have been closed.
What I do find odd is that all reports cease at this point. The previous version kept making the same report over and over again. I do not understand this, and suspect I have introduced a bug.

AT some point I will try to get all of my files up here in a zip, so you can have them, if you want.

Friday 25 September 2009

Timing and threads

Jackies carrots
Yesterday was market day and I forgot to take my camera with me. Sorry. But I will include an image from our market that, like Biddy Baxter, I took earlier. This one is from Jackie's famous fruit and veg stall. She's a real quick thinker, so no dithering!

Previous Episode

I said I'd get on to processing inputs from different sources. This is two problems really: one is, there might well be delays in transmission. In this case, it would be better to make regular reports (every 8 secs?) so you don't think your computer has died. You need a timer for this. The other is that your various sources have to be able to add words and counts to the same list without trading on each other and making a mess of the count. This suggests threading to me. Luckily, both timers and threads come from the same library in C#, as they've already forseen you might need both for some tasks. Whatever language you use, you will most likely need a special library for thread, because they go deeper than I want to into the workings of the machine in question. I am NOT a back-end developer (oooh missus!).

Thing is, I had to learn this as I went along, as I haven't even thought about simultaneous processes since Uni (and I'm too old to use that abbreviation, besides it was a Poly then). I turned to the one of my C# books I have only recently started reading again: Pro C# with .NET 3.0 by Andrew Troelsen. I usually refer to the more webby Pro ASP.NET 3.5 in C# 2008 by Matthew McDonald and Mario Szpuszta. Both are Apress books.

So, I now have a slightly different char reader called SlowedDownCharReader. This one uses a private random number to produce slight delays in transmission, which is perhaps a bit more like real life:

      Thread.Sleep(this._random.Next(200));

happens at the beginning of the fetchNextChar method. The random number returned is multiplied by 200 to give some hundredths of a second. This soon mounts up when you only get one char at a time! Note that the word Thread is already coming up. Random delays and timers are all things that affect the current thread of execution. Using these classes requires a using of System.Threading at the head of all relevant files.

Back in the main function, I've written a static setupTimer function. This is where it gets tricky. Since the operation we want to happen every 8 seconds is the WordList method makeReport, we need to create a C# delegate for the Timer to call. This has to be a void function passed a System.Object parameter:

    public delegate void makeReportOp(object state);

Here is the whole setupTimer function:

    static void setupTimer(WordList list, int secsToStart,int intervalSecs)
    {
        int millisecsToStart = secsToStart * 1000;
        int millisecsInterval = intervalSecs * 1000;
        WordList.makeReportOp reporter = new WordList.makeReportOp(list.makeReportCalledBack);
        TimerCallback timeCB = new TimerCallback(reporter);
        Timer everySoOften = new Timer(timeCB, null, millisecsToStart, millisecsInterval);
    }

First of all, the time before the Timer is called and the interval time are passed as seconds and then multiplied by 1000. No one thinks in milliseconds! Now the delegate is created and passed the WordList method to call. I have created a new report method, which sorts the list and writes it to console just as before but writes a short message before and after, so you can see what is going on. The method is locked, so that only one thread can access it (we are envisaging only one wordlist at a time). This message contains the thread number as well, because it is different from the main thread of the program. A TimerCallback delegate is created and passed the reporter delegate. Once that is done, all that is needed is to create a Timer object and pass it the callback, so it knows what to do. It is the Timer which works in its own thread of execution.

This all leads to a strange effect. Every 8 seconds (the interval I chose) a report is made to the console. These get progressively longer as more words get added. At some point, the fetchNextChar will generate its exception, print out a message to the console and stop the main thread. Nothing stops the timer except switching off the console window, so it will carry on printing the same list. I'm told killing threads is a difficult business. But this test case was imagining a continuous process of reporting on different streams coming in, so we won't worry about that.

Next time we'll set up 3-4 threads all putting their words into the same list.






Next Episode

Wednesday 23 September 2009

Chars, words and sorted lists


Pictures today are autumn things in the garden. First is some pink Sedum, looking much like pink cauliflower (you can get pink varieties). The second is bright orange Pyracanthus berries before the blackbirds scoff them all.

I've recently been working on a little task which is to run on the console. Not a website at all, much simpler. I found myself starting up my Visual Studio and setting up a project for the first time. Even, rather later, gathering my nice new classes into one place and making them into a library. Hot stuff! I should certainly create libraries more often.

The task was to create an instance of a character reader and assign it a chunk of text as a string. This can then be accessed, one char at a time. In a friendly way it lets you know you have got to the end by throwing an EndOfStreamException. The output wanted was a  list of words in the string sorted by number of occurrences and then alphabetically. After that it got more complicated but that will do for the next time.

I got my text from the first 3 paras of a classic short story "The Star" by Arthur C Clarke. Thank you Wikipedia.

I decided to create a class wrapper for a list of words called WordList. Also a WordListBuilder to process each character as it came and wrap things up at the end. This character reader class is called RealTimeCharReader, there will be another type later.
So:

    ICharReader myCharReader = new RealTimeCharReader();
    assignReaderContent(myCharReader);
    WordListBuilder myWordListBuilder = new WordListBuilder(myCharReader, 
         new WordList());

This means I want an instance of ICharReader, which implements IDispose, so has to have a Dispose() method, to make sure it cleans up. It also has to have a method fetchNextChar() which delivers a character, moves the pointer along and throws an exception when it is finished.

assignReaderContent is a static function allowing me to pass in whatever string I feel like in the Main() function.

WordListBuilder is going to have to take each char and either add it to a new word, or finish the word, eat any nonletter characters and start a new word. Each word is then added to the WordList. A Word is another new class containing a string and a counter. If a word turns up more than once, you can just increment the counter. Both the char reader and the wordlist are passed to the WordListBuilder to do the real work. Here is the call:
myWordListBuilder.buildWordList();
myWordListBuilder.BuilderWordList.makeReport();
buildWordList will process the list, makeReport will sort it and print the results to the console.

buildWordList consists of a try/catch structure containing a forever while loop which takes each returned char and decides what to do with it. The catch intercepts the EndOfStreamException and exits the while loop. Any other runtime exception in the reader gets caught by a more general catch. Either way the finally clause means Dispose is always invoked.

    public void buildWordList()
    {
        char nextChar;
        string nextWord = string.Empty;
                
        try{
            while (true){            
                nextChar = BuilderReader.fetchNextChar();
                if(char.IsLetter(nextChar)){
                    nextWord += nextChar;
                }
                else{
                   // treat all puntuation, digits and whitespace the same
                    if(nextWord.Length > 0){
                        completeWord(nextWord);
                        nextWord = string.Empty;                            
                    }
                }
            }
         }
             
         catch(EndOfStreamException ex){
             // add last word - even if it is partial - discuss[EOS]ion point?
            completeWord(nextWord);
            Console.WriteLine(ex.Message);
         }
         catch(Exception ex){
             Console.WriteLine(ex.Message);
         }
         finally{
             BuilderReader.Dispose();
         }
    }

    private void completeWord(string s){
        if(s.Length > 0){
            Word w = new Word(s);
            BuilderWordList.addNewWord(w);
         }
     }

The local variable nextWord is just a string, set to empty string. Since you have to add all words, including the last one - even if it has only partially arrived before transmission ceased, I added a short method completeWord, to be called whenever a non-letter is read or an EndOfStreamException is hit. This calls the WordList method addNewWord if there is anything in the string.


    public void addNewWord(Word w)
    {  
        // check word exists
        bool foundMatch = false;
        foreach (Word listWord in MyList){
             // if yes, then just increment count
             if (w.Content == listWord.Content){
                  foundMatch = true;
                  listWord.incrementCount();
             }
        }
        if (!foundMatch){
             MyList.Add(w);
        }
    }

Again, a simple method (as I prefer it!). It simply iterated through the list of Word objects in the member variable myList. If it finds a match it sets the boolean foundMatch to true and adds one to the count (or I could have used Count++). If it doesn't, then a new word is added to the list.

So now we have a list which contains a max of one entry for each word but it is not in order. I needed to create a class derived from IComparer and pass it to the sort function for the list of words. An IComparer clas needs to implement the function Compare. In this case we have to compare counts and then alphabetical order. It can be done in one pass, which I think makes life a lot easier!

    public class WordComparer : IComparer<word>
    {
        public int Compare(Word x, Word y)
        {
            if (x.Count > y.Count){
                return -1;
            }
            else if (x.Count < y.Count){
                return 1;
            }
            else{
            // they're the same word count, so sort alphabetically
                return string.Compare(x.Content, y.Content);
            }
        }
    }
The only unexpected part of this was that I assigned 1 as the result if x.Count was the greater. This gave me a reverse sorted list! So I swapped the values round. Notice for the alphabetical order I just use string.Compare, no further specification needed.

Nearly there! The sort function in WordList is very short:
private void sortList()
        {
            WordComparer wc = new WordComparer();
            MyList.Sort(wc);
        }
Passing an instance of IComparer enables the list to sort itself.

The last function simply iterates through the list and writes each word to the console, together with its count.

What's this all good for? Well, you might be monitoring someone's Tweets for rude words or buzzwords to display a Tag_cloud. The next time we'll consider monitoring several streams (Tweeters?) at once with possible delays in transmission.

By the way, I even managed to put all my classes in a library and make the small project refer to it. I'm quite proud.

I don't have any idea how to place a zip file here. I doubt if it would be that interesting at this stage but I ought to find out.

Next Episode

Sunday 13 September 2009

Haddenham Steam Rally

Well, this is going to be quite a hard blog to write. The main reason being that the whole point of going this year was to see Dunx and his embryo band playing in the (rather tiny) FenJam tent. And play they did. Ro took a video and now all I want is to upload it. Sigh ...

In the meantime, there are some great pix of prettily painted tractor wheels, handsome shire horses, steam engines (duh!) and so on.

Strange how exhausting it is being at Haddenham way above sea level. Haddenham is part of the Isle of Ely, so it is ooh about 300ft above the sea? Anyway, the wind whistles about and the announcer NEVER shuts up, so it's pretty hard on the head.



Here is the video, straight from YouTube. Dunx wrote the song, and it's called "Invincible". A classic break-up number, I'd say!

In fact what I am really supposed to be doing is reading Willa Cather's My Ántonia for a reading group tomorrow. A gorgeous book so far. I think I'd like to go to Nebraska now and lose myself in the tall wine-red grasses.

Thursday 10 September 2009

Damson Time!

You may remember a few posts back I put up a picture of some beautiful damsons growing in our tree. This is called a Shropshire Prune, and I bought it from Keepers Nursery in Kent three years ago.
At that time, I had to go away for the weekend to take the children to a competition and David had to plant the tree in a really pretty large square (not round!) hole. Since he was suffering from vertigo, he had to get a neighbour to make sure he didn't put it in at 45 degrees!
This year it is tall and fairly bushy. Thanks to great weather and huge amounts of water, it has produced a crop for the first time. I'd say about 8 kilos. To my surprise, the small, silver-bloomed dark fruit are very good to eat raw but that is not why I wanted them. When I do get round to eating jam, my favourite is certainly dark purple damson. I have a soft spot for sour cherry as well, perhaps I should find room for a cherry tree?
Anyway, over the last two weekends, my indefatigable husband has produced several jars of damson jam (front, one went to helpful neighbour), one large jar of damsons in rum(back) and reasonable amount of chinese plum sauce(right), which should work just great as a marinade for pork and other things. The rum fruit is for Christmas, if I can wait that long.
Recipes should follow, when I can prise them out of David. I know he made the rum one up. I am also waiting for my daughter to turn the remaining damsons in the freezer into dark red crumble. Me cook? Actually, I make curries and fab wholemeal bread. More another time ...

Friday 4 September 2009

Fun with IE7


Okay, this will be a super-boring post for those uninterested in making stuff work on IE7 (that's all of us, then).
On the left is a rather dull little form for entering an address. It is a cutdown version of an Asp.Net detailsView, which is why it is in table format (don't shoot me!). I set the size of the input field to 90% of available space, otherwise I get a short field. The whole table sits in a half-width column (may or may not be significant).

This is IE7's take on the same code (Opera and Chrome both looked like Firefox). As you can see, the font is too big, there are no borders and the input fields are shoved way over to the right. Aaargh! I'm trying to create a Content Management System and yes, most folks use IE7.
Inside my <!--[if IE]> brackets I had to make several changes.
  • font-size:small;
  • .detailView td, .detailView th, .detailView{
                border:1px solid black;
            }
  • input{
                width:20em;
            }
  • .commandRow input{
                width:80px;
            }
The font-size, well, whatever works. The border had to be set manually because, at detailView is an asp widget, I get little choice over the border (which is set to "1" in any case). I set the input to 20em, which is crap, because it doesn't fill the space. If I make it any bigger, it crowds out the label. And of course, I had to reset the size of the command buttons, or they'd be 20 ems as well.

This is the result. It's ok but not gorgeous. And it is only for adding things to a database.
Annoying, eh?

Wednesday 2 September 2009

Recent trip to Berlin

Thought I'd better scribble down something about last weekend's trip to Berlin, since I found myself buried in a thriller I bought in Hugendubel, Berlin's answer to Waterstones. Staff there very friendly. I homed in on one and asked her to recommend German Science Fiction writers. Nothing really appealed, so I ended up on the "Krimi" pile, picking out "Tannöd" by Andrea Maria Schenkel. Great stuff, several narrators but all pretty straightforward people, or I'd be lost. Lovely to read Bavarian voices, which sound so much like Austrian ones and remind me of the year I spent in Kärnten in my twenties.
I've included a picture of surely the best ice cream (sorbet, actually) in Berlin. Eismaufaktur. For my talent at reading detective stories and other intellectually undemanding books to flower most fully, it has to be in a good cafe. How could it be otherwise?
The second picture is from a gallery I like very much near the spanking new Hauptbahnhof. Confusingly, the gallery is called Hamburgerbahnhof but has been converted, like the Gare d'Orsay in Paris. You can't really resist Anselm Kiefer's plane made of soft lead, can you? No doubt it means something serious but I think it is cute. I found myself in the position of having to explain Joseph Beuys obsessions with fat and felt to my friend Lesley, when I have limited sympathy with him myself. She seemed to like him, which is something.
I felt totally at home in Berlin (don't say it's because I have spent most of my adult life in flat landscapes!) and it is soooo tempting to try and find a job there.
I also discovered I love white Rioja, though I only had one glass. Gorgeous.

Thursday 27 August 2009

MS SQL is too expensive


Hi,

Today's picture was taken by my daughter at the RHS Rosemoor in Devon last week. I love those big scary ferny things. They have large brush like flowers under all the leaves as well.

Spent much of yesterday researching how to become a "reseller" of hosting space. In other words, if I am going to write websites for people, I want somewhere to host their websites so I can keep an eye on them. I like ASP.Net and C#, which implies a Microsoft server and Ms SQL. There are lots of these around, some are very cheap. But ALL of the cheap ones have lots of truly scary reviews. Problem is, it looks like you have to pay a certain amount to Microsoft per MS database and there is no getting around that.

So why do I want it? MySQL is free and as far as I can see does the same job (is relational and all that). I can't use DotNetNuke but then I haven't yet managed to get that to run on my PC anyway. Looks like I can get a deal with a reputable host (for example 1&1 but it could be someone else) and use ASP.Net and MySQL (it runs on a Windows PC, it can run on a Windows server, surely?).

Ok, next step is how to connect to MySQL, the easiest way possible via Visual Studio 2008. I recommend this tutorial by Dr. Jay Krishnaswamy. This looks really lovely until you get to the part where you change the database type. MySQL just does not appear. The magic (and it took me ages to find this out) is on the MySQL website itself. Look through the downloads page (there aren't very many) and choose the latest stable connector for MySQL and .Net. This is an msi file. Scary though it is, I just downloaded it and let it do its stuff.

Next time I opened up VisStudio and had another go at configuring the data source, MySQL appeared in the list! After that it is all a matter of making sure your WAMP server is on and choosing the database and table you want. You also have to follow the above tutorial, to avoid errors (i.e, VisStudio does not like square brackets in SQL queries).

I now have a page which shows a gridview of a MySQL table on localhost. Next stop the external server!

Thursday 6 August 2009

Let's Get Going!


Well, I've been keeping a diary of my rather technical doings for some time now, do it would be useful to summarize now and again. To give some relief from webstuff boredom, I think I'll add a picture of something beautiful every day. This will get me out and taking pictures even if only in the garden! Otherwise I'd spend all my time in Starbucks.

Yesterday and today I have been grappling with the open source-ish AJAX Control Toolkit, specifically with the Calendar extender. Very nice little widget that pops up under a textbox so you can choose a date. Trouble is, it has preset css. So if, for example, you have set your font size a bit big, the calendar won't fit into its predefined space. In my case I lost Friday and Saturday. To make any changes to the CSS, I could find no other solution than to replace most of it (it ignores little bits). I copied suggestions from a site called Top54. Written last month, so up-to-date. I now have a large mass of extra class definitions in my CSS. Haven't they heard of the cascade? I also have a largeish date chooser with colours from my website and a rather wonky pair of substitute next/prev arrows.

Wierd how much time such seemingly little problems can eat up, eh?

The image today is two of our first crop of damsons. We've had the tree 3-4 years now and finally we see them. Gorgeous colour and bloom! With any luck at least one pot of dark crimson jam to come.