Saturday, December 17, 2005
Bug in Excel
Norway,no
Denmark,dk
Sweden,se
Germany,de
Norway,no
Denmark,dk
Sweden,se
Germany,de
Norway,no
Denmark,dk
Sweden,se
Germany,de
Norway,no
Denmark,
Sweden,
Germany,
Norway
Denmark
Sweden
Germany
If you look carefully, you'll notice that there is a comma missing in the last four rows. This means that it does not have two columns and the file is useless.
The workaround is to swap the two columns:
no,Norway
dk,Denmark
se,Sweden
de,Germany
no,Norway
dk,Denmark
se,Sweden
de,Germany
no,Norway
dk,Denmark
se,Sweden
de,Germany
no,Norway
,Denmark
,Sweden
,Germany
,Norway
,Denmark
,Sweden
,Germany
The bug is described here.
Err and get over it
Welcome to jansprograms
I will not post every day. Just when I feel like it.
You are very welcome to post comments.
Exiting a website
Today I stumbled upon a site that saves the url of the site you came from and offers an Exit link at its menu so you can return to it, regardless of how many webpages you have been visiting on the site.
A normal Back button will not work of course since it sends you only page to the previous page.
How it works? Don't know, but maybe the url you are coming from is saved in a table at entry.
Here is the site.
(Via The Home for Wayward Statisticians)
Duel Calculator
Below you may download the Duel Calculator written in MS Excel. You have to enable macros to run it. It has no virus. I know since I wrote it.
Processing - yet another free language

'Processing is a programming language and environment for people who want to program images, animation, and sound. It is used by students, artists, designers, architects, researchers, and hobbyists for learning, prototyping, and production. It is created to teach fundamentals of computer programming within a visual context and to serve as a software sketchbook and professional production tool. Processing is developed by artists and designers as an open-source alternative to commercial software tools in the same domain.'
The beta software for Processing 1.0 was released 20 April 2005. More
(Via paulofierro.com)
Interactive SQL tutorial

I have tested myself with 'a gentle introduction to SQL'. Questions are asked and you have to come up with the SQL that gives the right answer. You SQL is run on a database somewhere in real time.
You can practice SQL Server, Oracle, MySQL, DB2, Mimer SQL, PostgreSQL and Access.
An example:
Question:
A "good value" album is one where the price per track is less than 50 pence. Find the good value album - show the title, the price and the number of tracks.
Answer: (MySQL)
select album.title, album.price, count(song)
from album
JOIN track ON (asin=album)
group by asin
having price/count(song) < .50
Highly recommended. Both to learn SQL and for its pedagogical approach. The theory is available to those who needs/wants it by clicking a link on the question page. No correct SQL's are given, but the right records and fields for each question may be displayed to help one to come on the right track.
(Via J-Walk)
Excel is good for some things
1. A candidate who got more than 32.7% of the registered voters' vote was elected to the Legislative Assembly regardless of district.
2. A candidate who got more than 42% of the votes cast was elected to the Legislative Assembly regardless of district.
The big winner, in my mind, was Anthony Eden. 75% of those who voted in Bodden Town voted for him.
Look at the Excel file below for details. Maybe you discover other patterns.
Testing my Access skills
I did not know what to expect, so I practised writing queries as sql statements, instead of using Access' query generator.
In FoxPro 2.6 Developer's Guide I found 24 query questions with solutions. Already the second question stumped my Access skills:
'Determine how many states have at least one customer residing in them.'
The FoxPro solution is:
SELECT Count(distinct state) FROM CUSTOMER,
but that does not flush with Access.
I didn't find a solution before the interview, but I should not have worried. I was given three queries to do and the last one gave me some problems as I haven't done too many crosstab queries in my life. I got the columns and rows right looking, but the numbers were not correct.
'We are looking at the way you approach problem solving,' was the interviewer's comment, 'not that you get everything right.'
Personally I would hire me, not for what I know, but for my hunger and ability to get to know what I don't know.
We'll see if this firm sees it the same way. The verdict falls in a week's time.
---
When I find an Access solution to the problem mentioned in the beginning, I will post it here as a comment. If you beat me to it, shame on me!
Copying files
Yesterday, I wrote such a program in Access. Several copy jobs can be defined, edited, and deleted.

This is what it looks like afterwards in Windows Explorer:
Javascript fun
In my blog think again! I wanted to show 19 questions and answers in the game Twenty Questions. It would spoil the fun to display all 19 questions at once, so I started to make them invisible:
Everything in the div block "news1" will not be shown thanks to its style.
To display it at a click of a button, I need, suprise! surprise!, a button:
When the button is clicked, it calls the function jfx() with the value "true".
This is the function:
function jfx(status){
if (status)
{document.getElementById("news1").style.display = "block"};
}
To avoid using nineteen buttons, I used a variable:
var counter=1;
function jfx(status){
var b = "news"+counter;
if (status)
{document.getElementById(b).style.display = "block"};
if (counter == 19)
{document.getElementById("button").style.display = "none"};
counter++;
}
By putting the button itself in a div block, I can hide it when the 19th question have been shown.
To see the code in action, click here.
Greasemonkey
I can create a web page with html code people can see. People can create a web page with html for me to see.
The simple thing I never thought of is that I can filter what people send me. I can write code that does something to the html page I receive before it is being displayed on my monitor.
J-Walk enlightened me today: 'Greasemonkey could be the best thing to ever happen to the Web.'
He gives some links for learning more. And, a few hours later he came up with a 'useless' script. :)
I liked this quote:
"Greasemonkey is the new Excel: an inefficient way for end users to do anything. That's a compliment, BTW." - Mark Pilgrim
Ah, by the way. Greasemonkey is for Firefox browsers only. Which shouldn't be a problem, as it is the one I use (read: the best browser out there).
Yes, you guessed it. My mind is warming up its cylinders to come up with a problem the Greasemonkey may be a solution to. The wrong way around, I know, but what can you do?
Eat your own dog food
Today I found the answer. From time to time he writes interesting article on programming. Here is an excerpt from something he wrote more than four years ago:
'Eating your own dog food is the quaint name that we in the computer industry give to the process of actually using your own product. I had forgotten how well it worked, until a month ago, I took home a build of CityDesk (thinking it was about 3 weeks from shipping) and tried to build a site with it.
Phew! There were a few bugs that literally made it impossible for me to proceed, so I had to fix those before I could even continue. All the testing we did, meticulously pulling down every menu and seeing if it worked right, didn't uncover the showstoppers that made it impossible to do what the product was intended to allow. Trying to use the product, as a customer would, found these showstoppers in a minute.'
To use your application as a customer is a good advice. I developed sharealink more than a year ago and use it every day. By using it I found some irritating features that have been ironed out, and a list of improvements I haven't had time for yet.
Who is Ruby?
'Ruby is the interpreted scripting language for quick and easy object-oriented programming. It has many features to process text files and to do system management tasks (as in Perl). It is simple, straight-forward, extensible, and portable.
Oh, I need to mention, it's totally free, which means not only free of charge, but also freedom to use, copy, modify, and distribute it.'
Fighting hard coding
One solution is to put the information in an ini file. Many people scorn ini files, I don't.
Another solution is to put the information in a table. My table has two fields: cname and cvalue.

select cname, cvalue from (ctable) into array a_temp
CLOSE databases
for i = 1 to _tally
cdatatype = left(a_temp(i,1), 1) && c, l or n
do case
case cdatatype = 'c'
this.addproperty(alltrim(a_temp(i,1)), alltrim(a_temp(i,2)))
case cdatatype = 'l'
this.addproperty(alltrim(a_temp(i,1)), iif(ALLTRIM(lower(a_temp(i,2))) == '.t.', .t., .f.))
case cdatatype = 'n'
this.addproperty(alltrim(a_temp(i,1)), val(a_temp(i,2)))
case otherwise
MESSAGEBOX("Corrupt " + ctable + ". The program will end.", vbokonly + vbinformation, "Error")
RETURN .f.
ENDCASE
ENDFOR
The first character in cname stores the data type. The code is written in Visual FoxPro 8. Each piece of data is stored as a property in an object I have open as long as the program is running, making them behave like global variables.
I think this is a clever way of dealing with data of this kind. Even better, I think it is my own invention! :) At least, I can't remember I read about it somewhere.
Haskell - another language

I discovered Haskell the other day.
It has its admirers:
'WOW! I basically wrote this without testing just thinking about my program in terms of transformations between types. I wrote the test/example code and had almost no implementation errors in the code! The compiler/type-system is really really good at preventing you from making coding mistakes! I've never in my life had a block of code this big work on the first try. I am WAY impressed.'
I'll check it out when I find the time.
Adding time
How much is 5h 49 m + 55m (h = hours, m = minutes)?
If you add 5.49 and 0.55 you get 6.04, which is wrong.
However, if you custom format the cells to [h]:mm and write 5:49 in one cell, and 0:55 in another, you get the correct answer 6:04. The [h] is used so the time is not added modulo 24. 20:50 + 10:04 = 06:54 if h:mm is used, but equals the correct 30:54 with [h]:mm.
If you are lazy, as I proudly am, you don't want to type 05:49 to enter the time. The 0 shouldn't be needed and the : neither. The answer is to use the custom format 0":"0#. Now, if you type 5, 0:05 appears. Likewise, 12 gives 0:12, 549 gives 05:49, 1545 gives 15:45.
Here comes the bad news. You can't give a cell two custom formats at the same time. In this case you have to pick between [h]:mm and 0":"0#. If you choose the first the times add up, but you can't be lazy. If you use the latter the times do not add up, but you can be as lazy as hell.
Allen Wyatt suggests a way out.
'... use another column to show the entered digits converted into a time. All you need to do is use a formula to do the conversions. For instance, if the time you entered was in cell A3, you could use the following formula in a different cell to do the conversion: =(INT(A3/100)/24)+((A3 - (INT(A3/100)*100))/1440)'
I would type the times lazily with the format 0":"0# and have it automatically copied to a cell formatted with [h]:mm format I would use for adding.
If I have hundreds of cells with times to be added, the solution is a bit laborious, so I looked for something else. This was my idea: Format all cells with the general format. When a time is entered lazily, like 549, let code convert it to 05:49 and format the cell to [h]:mm. This is my code:
Dim nrow As Integer
Dim ncol As Integer
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If nrow <> 0 And ncol <> 0 Then
If InStr(Application.Cells(nrow, ncol), ":") = 0 Then
Application.Cells(nrow, ncol) = ftime(Application.Cells(nrow, ncol))
Selection.NumberFormat = "[h]:mm"
End If
End If
nrow = Application.ActiveCell.Row
ncol = Application.ActiveCell.Column
End Sub
Private Function ftime(t As String) As String
' example: '5' -> '00:05'
' example: '12' -> '00:12'
' example: '540' -> '05:40'
' example: '1123' -> '11:23'
t = Right("000" & t, 4)
ftime = Left(t, 2) + ":" + Right(t, 2)
End FunctionIt works well as long as one stays inside the cells where time is added. To avoid problems for other cells one might test if the active cell is in the range of time cells or not.
I will post this problem on a user group and see what people have to say.
Subform in php
One new challenge was how to get a subform over. It looks like this in Access:
This is what I came up with in the browser:
Three queries was needed. One to display the fee records for each year, another to display the years in the combo for the chosen member, and a third to give the content of the fields for the chosen year.
I liked the solution.
Mail merge with MS Publisher
I never planned to ever mail merge with MS Publisher, but since the template for the students' report card was made in Publisher I more or less had to give it a try.
I put the data in MS Excel.
The only interesting problem was how to achieve these check marks:

I came up with this:

The formula checks if the rightmost character of the column titles (A4, A3, ...) equals the number in K2 (4, 3, 2, or 1). If it is, a ĂŒ is printed, which in font Wingdings is a check mark.
In MS Publisher I had the fields A4, A3, ..., and they were empty or not depending on the value of K2. So all I had to do for each student was to put a number from 4 to 1 in K2 for the class work effort. Homework effort was put in L2, etc.
Even more exciting
Today, I did something even more exciting. I wrote a Visual Basic program that runs on my computer and accesses my database in Hong Kong. To achieve it all I had to do was to enable the database for external access in its control panel, download the MyODBC driver, and use this connect instruction in Visual Basic:
conn.Open "DSN=Hong Kong;server=simpler-solutions.net;uid=???;pwd=???;database=janbase"
I replaced the ??? with my username and password.
To improve my economy slightly my next project is to access my bank's database.
Javascript is my new hero
An example. In my program sharealink the link may have a note describing the link and one or more comments from people who has visited the link. Sometimes it is nice to turn the notes and comments off.
I knew hov to turn one div block on and off, but not a whole bunch of them. Paulo Fierro, came to my rescue. By using
document.getElementsByTagName("div")
he created a loop that turn off or on all divs that started with 'note' and 'comment'. To see the code click the sharealink link above and view the page source. To see the code in action, just click the links Toggle notes and Toggle commentsMy Internet bank uses a lot of javascript to make visits to my account a more pleasant one. The nice thing is that the code is right there under my nose. I choose view source and learn a lot. :)
Can I flash?
Some of the games can be played, move for move, thanks to a Flash application. I don't know for how long the link will work, so here is a picture, and here is a link to the company.

The question is, of course, why can't I write this kind of software. Why shouldn't I find time to flash a bit. I have even been told that Flash and databases are friends.
The hard way, because it is easier
I just read it in a Google Group, and I share the sentiment:
'the first thing you have to decide is not to use these advantages because the only thing they give you is a headache'
Should I use a dbcombo or a standard combo in Visual Basic? Should I use a wizard to create a form in Access or should I do it manually? Should I use Excel for my database or should I use a database program?
If you only want to make one step, the easy way is fine. But, if you want to take two the harder way is easier. The funny thing is that people who only thought they would take one step, suddenly realises they need two so they have to go back to square one, and maybe unlearn a few things on the way.
My first javascript program
I found a solution, that later turned out to have a flaw, and wanted to illustrate the solution in a javascript program you can play with here.
The program has a few flaws on its own, but they will be ironed out in the next few days as I learn more.
To write the code I used the examples at w3school for inspiration. The coding took me a few hours. These syntactical details hampered me the most:
- I did not know how to write a for loop. I used comma instead of semi colon and got the order of the three elements in the beginning wrong.
- It took me some time to realise that an array likes [] better than ().
- I discovered that the elements of an array is not initialised to 0 when it is declared.
- I had some problems with lining up the { and } in a long if then else endif statement. The error message complained about an instruction far later than where the error was.
- I had some trouble remembering when to use == and when to use =.
- I tried to run an empty do while loop. It didn't like that. When I added nothing, i.e. { }, everybody was happy.
- To pick a random prisoner I found this at Google, Math.floor(Math.random() * prisoners).
- I still do not know how to keep the textbox and the button when clicking Start.
- I still don't know why the code doesn't stop to run.
- In Visual Basic loops often have the instruction doevents to allow the cpu doing other thing than the program so the machine won't freeze. This does not seem to exist in javascript. Some sites talked about settimeout, but I failed to understand it. The problem was that when I used a 'do while (solution not found)' the program made Mozilla freeze. I had to settle for a for loop.
- if ((beenthere[leader]) && (switchis == 'down')) seemed to behave better than if (beenthere[leader] && switchis == 'down')
Conclusion: great to learn a language by solving an intriguing puzzle and looking at examples and not descriptions for the right syntax.
Here is a sample run:
---
start of game
there are 5 prisoners, (prisoner# 0 to prisoner# 4)
switch is unknown
0 up
the leader was sent to the cell for the first time
count = 1 (added the leader, prisoner# 0)
4 down 3 down 2 down 1 down 4 down 1 down
count = 2 (added prisoner #4)
0 up 0 up 1 down 4 down
count = 3 (added prisoner #1)
0 up 0 up 2 down 1 down 1 down 1 down 1 down 3 down 2 down 3 down
count = 4 (added prisoner #2)
0 up 4 up 3 down
count = 5 (added prisoner #3)
release the prisoners!
25 moves to the cell
---
If you read the problem and comments at a school yeard blog you may understand what all this means. :)
Sensitive table

About ten years ago I wrote an Excel spreadsheet that today needed some maintenance. The request was simple, 'add space for ten more teachers.' The hard part was to remember how on earth I had created the spreadsheet.
One hour of research revealed that I had used sensitive tables, something I have not used since.
The first column contains the teachers' ids and the second column how many lessons they have been assigned during a week. There are eight periods per day and the other columns show if they are teaching (1) or not (blank).
The cell with # in it contains this formula:
=COUNTIF(TIMETABLE,DUMMY)
where TIMETABLE is a range on another sheet that contains amongst other things all the teacher ids for every period of the day during a week while DUMMY is the name of a cell in the first column below all the teacher ids.
The cell with 1 in it for Monday contains:
=COUNTIF(MON1,DUMMY)
where MON1 is a column on another sheet listing the teachers who teach first period on Monday.
Now we are ready for the exciting part! The range from the blank cell above AE down to the row with the last teacher and the column with period 8 on Friday I created to be a sensitive table by choosing Data - Table on the menu and A93 (the address of DUMMY) for Column Input Cell (Row Input Cell I left empty).
When I click on any of the cell the formula displayed is
{=TABLE(,A93)}.
I found this solution rather elegant, although it was hard to gather how I had done everything ten years ago. Excel's help on this is meager and I hadn't taken any notes. Which is why I jot this down in case I want to use sensitive tables again. Here is a web page that helped me a bit.
How stupid I am
Private Sub Form_Load()
Me.KeyPreview = True ' so the form receives keystrokes before the objects
End Sub
Private Sub Form_KeyPress(KeyAscii As Integer)
If KeyAscii = 13 Then
' find out which object has the focus
' find the tab index to the object
' increase the tab index by 1
' find the object with that tab index
' give the object focus
KeyAscii = 0 ' Ignore this key.
End If
End SubA quick Google Group search made me kick myself behind. The five commented lines above can be replaced by one single instruction:
SendKeys "{tab}" ' Set focus to next control. Translated: let the Enter key pretend it is a Tab key.
Learning by doing
Till today I had to put all my projects in the same folder as I didn't know how the server would find them otherwise. Obviously, it is easier to keep each project in its own folder, and on the usb stick and not on the hard disk in case it dies on me.
A question on a Google group taught me how to do it.
Here is my summary:
1. I opened the file C:\WINDOWS\system32\drivers\et
127.0.0.1 localhost
to
127.0.0.1 localhost calendar
2. I opened the file ...\xampp\apache\conf\httpd.co
NameVirtualHost *:80
DocumentRoot "E:\programming\php programs\dx"
ServerName calendar
3. I copied all the files in my dx project to the folder
E:\programming\php programs\dx.
4. I restarted apache.
Vuaw! The file was found and did its job as when it was in its original folder. In short: it worked!
Fast data entry

Let's say you have to add codes like this all day:
| 8 - 5 k |
| 8-5 d |
| 5-cl p |
| 12-10 s |
8 - 5 k means that the employee worked from 8 to 5 in the kitchen, etc.
Probably you would find it tedious and mistakes are bound to happen.
Imagine you could type in 1, 2, 3, 4 instead. When you type 1, 8 - 5 k appears, when you type 2, 8-5 d, etc. That would save time and improve accurracy.
I created a worksheet called "tabla" with a range called tabla, item, valor, and max.
The range tabla has two columns. First columns is for the codes 1, 2, 3, ... and the second column is for the values 8 - 5 k, etc.
Item is a single cell with no formulae.
Valor is a single cell with the formulae =VLOOKUP(item;tabla;2;FALSE).
Max is a single cell with the formulae =MAX(A2:A16).
This is my code:
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
If Sh.Name <> "tabla" Then
If Target.Value > 0 And Target.Value <= Range("max") Then
Range("Item") = Target.Value
Cells(Target.Row, Target.Column) = Range("valor")
End If
End If
End Sub
Every time you type 1, 2, 3, ... it is replaced by the corresponding code.
Note that the user does not have to change the code. All he has to do is to change the values in the range tabla.
I am sure this can be done in many other ways, but I found this one neat.
My major problem in writing the code was to realise that I had to test if the sheet name was "tabla".
Fast data entry - Part 2
In Excel if you want 'police' to appear when you type 'pl' all you need is a table that pairs the two up. In some languages, like php, you can have arrays A where A('pl') = 'police', but I don't think Excel allows it.
For the moment I will settle with numeric codes 1 to 100, so A(1) = 'police'.
Here is the code for my new version of 'Fast data entry' from the other day.
---
Option Explicit
Const Max As Integer = 100
Dim A(Max) As String
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
Dim I As Integer
If Sh.Name <> "tabla" Then
For I = 1 To Max
A(I) = Worksheets("tabla").Cells(I, 1)
Next
End If
End Sub
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
If Sh.Name <> "tabla" Then
If IsNumeric(Target.Value) Then
If Target.Value > 0 And Target.Value <= Max Then
If A(Target.Value) <> "" Then
Cells(Target.Row, Target.Column) = A(Target.Value)
End If
End If
End If
End If
End Sub
---

This is the substitution or code table the user will edit. As soon as the user goes to a new sheet, the values are read into a public array.
Why is this version better than the previous one? It uses no range names the user may inadvertently erase. Apart from that I don't think it is much better than the previous one. Actually it is a bit worse in a sense since the previous version allowed for 'pl' as code for 'police' while this one requires a number.
Anyway, it gave me some practice using Excel.
One thing I learnt was that if you write 'isnumber' it is changed to 'IsNumber' making you believe that it is a part of the language. When you select it and click F1 you are told that Help is not installed. When you select 'IsNumeric' and click F1, Help opens. Definitely a bug. In Excel.
Multi column combo box in Visual Basic

In MS Access a combobox can have several columns. Typically two columns are used, one for the id (which is hidden), and one for a descriptive field (which is shown).
Example: Show the name of the employee, but hide his id.
Strangely enough, in MS Visual Basic a combo box can't have more than one column.
One workaround is to add the descriptive field and the id into one long string, padding the descriptive field so it is say 200 characters long, making the id out os sight, but easily available using a substr() function.
Another way is to create your own multi column combo box. Patrick van Olderen did so. I just downloaded his version 11 of the control from 2002. It comes with an example test program in .exe form and also as vb project so you can study how the control can be used with code.
To register the ocx was a swift operation. Windows + R followed by:
regsvr32 "E:\programming\visual basic\ocx\ComboBoxLB.ocx"
(By the way, E is my 40GB iPod that since yesterday has started to work for me as my data storage, slightly out competing my 1GB Usb stick that was full.)
As always, Google groups, helped me to find the ocx and learn how to register it. Now, of course, all tips and tricks have been pasted into my treepad file on Visual Basic.
Programming is the easy part
The essay.
How to stay in a combo box after pressing the Enter key

I have a combo box called cmbrefnumber. The user will type a refnumber, or part of it, press Enter, and data for that refnumber will be displayed. Since the user most probably would like to enter another refnumber I would like the combo box to have focus after Enter is pressed.
This is how I achieved it:
Private Sub cmbrefnumber_AfterUpdate()
...
gbcmbrefnumberafterupdate = True
End Sub
Private Sub cmbrefnumber_Exit(Cancel As Integer)
If gbcmbrefnumberafterupdate Then
gbcmbrefnumberafterupdate = False
Cancel = True
cmbrefnumber.SelStart = 0 ' selects the refnumber
cmbrefnumber.SelLength = Len(cmbrefnumber.Text)
End If
End Sub
gbcmbrefnumberafterupdate is a global variable that remembers if the user has typed a new refnumber. If he has, the exit will be cancelled and gbcmbrefnumberafterupdate is set to false such that if no changes are made exit is permitted and the next control in the tab order gets the focus.
I found the answer here.
I don't know, so let me answer that question!
Today, I got an email from a friend re userforms. His problem was how the content of one combo box can change when the user makes a pick in another combo box.
A few Google searches not only solved my friend's problem, but it also taught me quite a bit about userforms.
RodMcKuen once told his audience that he was about to publish a new book of poems. Shortly, he got many requests for the book. The problem? He hadn't written the book yet. 'So, every night I went home and wrote poems for the book.'
How to add code to a page that doesn't allow code
I live in West Bay which is thirty minutes from the tennis club in South Sound. How do I know if the courts are dry before I set out on my journey to the club? I could call, but that costs cell phone money and disrupts the club manager.
Another solution is to have a web page the manager updates displaying info on the courts, any details, and the time it was updated.
The control panel for the weather page is here. Only the club manager knows the password.
The weather page members can check out is here, or they can look in the upper-right corner of the club's website.

How does the box change from 'The courts are dry!' to 'The courts are wet!' when the blog host doesn't allow any programming?
The box is an image sitting on my server. I change the image when the club manager changes the weather report in the control panel. The control panel also sits on my server and allows, of course, programming.
Array formula saves the day

Three employees are sick (S) or have vacation (V) on various days in August and September.
I would like a formula to calculate the total number of sick days and vacation days for each employee for the range B4:C6.
I visited Mr Excel here and visited pages with countif in them. This page held the answer.
In B4 I typed the formula =SUM((people=$A4)*(DATA=B$3)) and pressed Ctrl+Shift+Enter as it is an array formula.
people is the range A7:A18 and DATA is B7:I18. I copied the formula to the other cells in B4:C6 and that was it!
Moral: you don't have to know a lot if you know a little and Google is not far away.
