Tuesday, June 09, 2026

Round the bend

This morning I was passing from the bathroom to the lounge via the music room when a song on the radio caught my attention. It sounded like Nick Drake although I knew that it wasn't as I didn't know the song. The vocal sounded like Nick and the arrangement sounded like 'Riverman', so I 'shazamed' the song and was told that I was listening to 'Round the bend' by Beck.

In the past I tried listening to Beck as I had been given the impression that his songs would fit my taste, but obviously the selection to which I listened didn't push my buttons. In short order, I discovered that the song comes from his 2002 album, 'Sea Change'. Reading the comments on YouTube, I saw that I was far from the first who made the connection between this song and 'Riverman'.

Listening to the other songs on this album, I have yet to find another song that sounds so mysterious. It transpires that there is another song on the album that I recognise, 'Lost cause', but it's not a song that gets me excited.

Another song that has caught my attention lately is "It's not just me, it's everybody" by the artist trading under the name Weyes Blood. This is on my wife's playlist, although she doesn't recall how she found it. This song is reminiscent of Joni Mitchell, primarily in the chromatic mediants. From a music theory point of view, this song is very interesting, and the arrangement builds and builds. The vocal starts low but ends up fairly high. The only thing that I find annoying is the staccato piano; although the chords played vary (I don't know what key the song is in, but if we say it's in D, then the chords start as D, D6, D, D6), their rhythm doesn't and I would have preferred some variation - some syncopation or even not playing for a bit. It's a shame as this slightly ruins my enjoyment of the song.

Again, I listened to other songs of the singer, but didn't find anything else that caught my interest.



This day in blog history:

Blog #Date TitleTags
17809/06/2009Inter-program communicationProgramming
25309/06/2010Post mortem on my Economics examMBA, Economics
59209/06/2013Barcelona log (4): In search of DaliHoliday, Barcelona
86109/06/2015LinkedInDBA
86209/06/2015Vinyl log 13 - 9 JuneVinyl log
95409/06/2016An advanced - and possibly useless - technique in PriorityPriority tips
104209/06/2017Rodos log 5: SymiHoliday, Rodos, Greece
114509/06/2018Italy 2018 - The market, Mole AntonellianaHoliday, Torino, Italy
123109/06/2019Crazy weekJewish holidays
151209/06/2022Italy 2022: OstuniHoliday, Italy, Bari

Monday, June 08, 2026

Just like 'old times'

Even though I was taking a day off today*, I got up at 5:30 am and took the dog for her early morning walk. By about 6 am, she had done what she had needed to do, and we were about a third of the way through our walk. At this stage, my phone started emitting a sound that I couldn't place at first: I took it out of my pocket and saw that the home guard were dispaying a warning message about an imminent air raid warning. So I immediately turned and we started walking back home at an increased pace, not stopping for any sniffing around. At about a distance of 100 metres from my home, the air raid warning starting sounding - it's quite frightening to hear it when outside. People from the building neighbouring ours were coming down the stairs and heading for the nearest air raid shelter whereas the dog and I were half running home in order to get to our secure room. There are only a few buildings on my side of the kibbutz that have a secure room so we are quite privileged in this respect.

After the all clear signal had been given (via telephone), we were free to exit the room. I had intended to go swimming this morning at 7 am, and I saw no reason not to go. If the pool was closed then all I would have done was complete my early morning walk. By 7 am, I was at the pool and saw the life guard open up; there was only me and another swimmer there. At that hour, the air temperature is much closer to the water temperature, so the cold water didn't bother me. After swimming a few lengths, I thought that I heard an odd sound, so I treaded water for a bit, then carried on. A few minutes later, the air raid sirens sounded again.

So it was out of the pool and into an air raid shelter that was conveniently close to the pool. When I went down into the main room, I was surprised how many people were there; presumably the odd sound that I had heard before was the early warning. A few people made some comments about my attire, but I wasn't paying attention so I didn't realise that they were talking about me. After about 20 minutes, the all clear sounded and we all exited the shelter. By this time, I had lost interest in swimming, but I had to go back to the pool to pick up my headphones, cap and robe; the other person who had been swimming with me was back in the water.

On the way back home (I live on the opposite side of the kibbutz from the pool), three or four people stopped me and asked if the pool was open. I repeated my story. Later on, a message appeared on the electronic notice pool that all pools in our general area would be closed for the rest of the day.

So it's just like 'old times' of the earlier wars with Iran and Yemen from the past year.

* A few weeks ago, I noticed that I had accumulated many days of holiday. As I will soon be retiring, these days would be turned into money and as a result I would be paying a great deal of income tax for this extra payment. I also receive two days holiday a month, so if I did nothing, I would end up with 36 days of holiday. As a result, I've been taking one day of holiday each week.



This day in blog history:

Blog #Date TitleTags
8208/06/2007Rise up like the sunFairport Convention, Albion Band, Time signatures
59108/06/2013Barcelona log (3): Rain stopped playHoliday, Barcelona
104108/06/2017Rodos log 4: Lindos and the seven springsHoliday, Rodos, Greece
114308/06/2018Italy 2018 - The best chocolate in the worldHoliday, Peppermint, Torino, Italy
114408/06/2018Italy 2018 - Getting to know TorinoHoliday, Torino, Italy
132308/06/2020The background behind another song that is used for Israeli folk dancingKibbutz
139508/06/2021A new Yoni Rechter songbookYoni Rechter
151108/06/2022Italy 2022: Corso Cavour (2)Holiday, Italy, Bari
162708/06/2023Post doctorateNutrition
194808/06/2025Diet, drugs and dopamineNon-fiction books, Nutrition

Wednesday, June 03, 2026

Why zebras don't get ulcers

Over the past week, I've been reading this very interesting (for me) book. In order not to misrepresent the author, I'm going to quote some paragraphs from the opening chapter.

For animals like zebras, the most upsetting things in life are acute physical crises. You are that zebra, a lion has just leapt out and ripped your stomach open, you’ve managed to get away, and now you have to spend the next hour evading the lion as it continues to stalk you. Or, perhaps just as stressfully, you are that lion, half-starved, and you had better be able to sprint across the savanna at top speed and grab something to eat or you won’t survive. These are extremely stressful events, and they demand immediate physiological adaptations if you are going to live. Your body’s responses are brilliantly adapted for handling this sort of emergency.

The half of the autonomic nervous system that is turned on is called the sympathetic nervous system. Originating in the brain, sympathetic projections exit your spine and branch out to nearly every organ, every blood vessel, and every sweat gland in your body. They even project to the scads of tiny little muscles attached to hairs on your body. If you are truly terrified by something and activate those projections, your hair stands on end; gooseflesh results when the parts of your body are activated where those muscles exist but lack hairs attached to them. The sympathetic nervous system kicks into action during emergencies, or what you think are emergencies. It helps mediate vigilance, arousal, activation, mobilization. To generations of first-year medical students, it is described through the obligatory lame joke about the sympathetic nervous system mediating the four F’s of behavior—flight, fight, fright, and sex. It is the archetypal system that is turned on at times when life gets exciting or alarming, such as during stress. The nerve endings of this system release adrenaline. When someone jumps out from behind a door and startles you, it’s your sympathetic nervous system releasing adrenaline that causes your stomach to clutch.

The other half of the autonomic nervous system plays an opposing role. This parasympathetic component mediates calm, vegetative activities—everything but the four F’s. Sprint for your life across the savanna, gasping and trying to control the panic, and you’ve turned the parasympathetic component down. Thus, the autonomic system works in opposition: sympathetic and parasympathetic projections from the brain course their way out to a particular organ where, when activated, they bring about opposite results. The sympathetic system speeds up the heart; the parasympathetic system slows it down.

Another important class of hormones in the response to stress are called glucocorticoids. 

The body synthesizes these glucocorticoids, but we can also be given synthetic glucocorticoids, a good example being Prednisone that is a potent synthetic corticosteroid used to quickly reduce inflammation, suppress an overactive immune system, or replace natural cortisol. It is prescribed for a wide variety of conditions, including severe allergies, asthma, arthritis, and autoimmune diseases like lupus. 

The neurologist1gave me a referral for a head CT, using a contrast dye. In Israel (and probably elsewhere), someone who has a bad reaction to such dyes is considered to be allergic to Iodine, although this is not accurate as iodine is a required micronutient for the thyroid gland. Reactions to intravenous X-ray/CT contrast media are typically caused by the physical properties (e.g., hyperosmolarity) of the solution itself, not the iodine it contains. I am not sure whether I am 'allergic to Iodine'; it is written in my medical history and so everyone has to be careful. I underwent a procedure some 40 years ago to do with my kidneys and had a bad reaction to the 'iodine' although whether that is considered to be severe enough to be an allergy is uncertain. I have an appointment with an allergy doctor in August to settle this once and forever.

The connection between this scan (which was done yesterday) and the glucocorticoids is that I had to undergo a 'preparation protocol' that involved taking prednisone three times at various hours of the day along with another medicine an hour before the test. Everyone at the hospital checked that I had taken the medicines although obviously they had to rely on my answer. 

I am going to go into detail about what I felt from the scan onwards, primarily so that I will have it documented. During the test itself, the only abnormal thing that I felt was as if part of my testicles had been lowered into warm water; the rest of the body felt fine. My hands were shaking slightly but that's something that I've noticed over the past few weeks. After I got home, I took the dog for a walk then had a light supper. I felt slightly warm but I thought that this was due to walking the dog. By the time I came to measure my blood pressure at 9 pm, I was surprised to see that it was high (relatively for me) at 125/82 with a pulse of 102. For comparison, the readings on Sunday evening were 103/78 and pulse 77. When I got into bed, I felt quite warm, despite the air conditioner, and slept for some time uncovered.

Obviously the prednisone had activated the sympathetic nervous system, and the iodine was having its effect.

Going back to zebras and why they don't have ulcers: humans have both external sources of stress and internal souces, or psychological stresses. Unfortunately, the body can't distinguish between the two sources and so the sympathetic nervous system gets unnecessarily mobilised, moving blood to our arms and legs and taking it away from other areas of the body. One familiar source of psychological stress is how much control we feel we have over our lives, otherwise known as locus of control. Those with a low locus of control have more stress than those with a high locus. 

My job affords me with a very high locus of control, but I remember that when I was in the army (compulsory service and reserve duty) I had a very low locus, and I used to say that if something were about to happen and I could think of two alternatives, the army would always choose a third option which would be worse than anything that I could think of. 

Internal links
[1] 2095



This day in blog history:

Blog #Date TitleTags
95203/06/2016Dave Swarbrick, RIPObituary, Fairport Convention
150503/06/2022Italy 2022: pre-flight checkHoliday, Italy, Bari
177103/06/2024Cruise log #2: RodosHoliday, Rodos, Greece
194303/06/2025A cheap source of ErythritolErythritol

Saturday, May 23, 2026

2026 swimming

As I wrote1 last year, as usual, the swimming pool opened at the time of the Harvest festival (known as Whitsun to our Christian friends); this seems to be the earliest date for some time as normally the pool doesn't open until June. For the first two days, the pool opened at 10 am, which is an inconvenient time for me, but today, there was health swimming at 8:30 am, which is much better for me (actually I would have preferred even half an hour earlier). 

Several months earlier, probably after the removal of yet another growth, I considered how I can minimise my exposure to the sun. When I'm swimming, my back is exposed and I've had quite a few growths removed from there. The answer was a Quick-Dry Swim Shirt Short Sleeve that I ordered from Temu about six months ago. I hadn't tried wearing this shirt until this morning so there was a slight worry that it might not fit, but the size was fine. As opposed to the sort of swimming shirt that I would wear 20 years ago that would flap around in the water and slow me down, this one fit snugly (without being too tight) so it was as if it wasn't there. I should note that the colours in the accompanying photograph have been manipulated; the original was too dark.

By 8:30 am, I was at the swimming pool, alone; the lifeguard opened the gate and I went in. I suspected that the water would be cold but I didn't expect it to be so cold! The first step down the ladder where I'm standing had the water cover my ankles; I waited a minute or so to acclimatise. Then another step down the ladder and my calves froze up. One more step and my thighs were covered; then I let go and floated for a bit. The water was freezing! Of course, I paid less attention to the cold once I started swimming. My body remembered was it was supposed to do and the only ache came from my neck (normally my left arm starts aching after a few lengths).

I swam two lengths, had a short rest. swam another two lengths and a rest, etc. In total I swam 10 lengths. That was enough for this year's debut performance. I should note that I was the only swimmer in the pool; my normal pool-opening companions were strangely absent. I sent a WhatsApp message to one of them and received an answer a minute ago: she was at her brother in law's flat in Tel Aviv. She also suffered from the cold when she was in the pool (I don't know when). Two people turned up only as I was preparing to leave and they too were surprised that I had been the only swimmer.

I had dug out my bone conducting headphones2 a few days ago and fully charged them in preparation. The set list for today was two of my songs, 'Night scented stock' by Kate Bush, 'Katie's been gone' by The Band, and 'Stormbringer' by John Martyn. Another song might have started just as I finished but I don't recall. I often find it hard to recognise the songs at first because they play in a completely random order. 

I've been suffering quite a bit from stomach problems over the past few months and there have been the odd hint about them here. As a result, I abandoned my time restricted eating, as I found that eating something in the early evening helped with the aches. I saw a gastro-enterologist about six weeks ago who ordered a gastroscopy; this didn't reveal anything interesting, although a polyp was removed and sent for biopsy. I saw the GE doctor again who wasn't impressed by any of the possible findings of the gastroscopy. The one strong recommendation that he made was that I should double the dosage of omepradex; I always thought that this worked like paracetamol - the effect of each pill would wear off after some hours - but apparently not. I can definitely say that the days when I have 'gastric distress' are becoming fewer, and when they do occur, they are much milder than some of the bad days that I had before. All this is to say that I will be able to resume time restricted eating on the days when I go swimming - and this year I intend to swim frequently. Last year, time restricted eating helped reduce my weight and I don't eat on pool mornings until after swimming.

On the other hand, the new prophylactic medication Depalept3 that I have been taking to prevent migraines has worked well in that respect but seems to have caused my weight to balloon, although this may be water retention as my wife says that I don't look any worse. The medication has also had a very interesting effect on my sleep apnea: the central sleep apnea have almost completely disappeared (I didn't have even one such event in the past week) and obstructive apnea have also almost completely disappeared - two in the past week. Whatever the CPAP measures as deep sleep has also been affected: whereas this used to be in the range 0 - 20 minutes a night, now it's 50 - 120 a night. I shall mention these side effects to the neurologist in the follow-up appointment next month.

Internal links
[1] 1946
[2] 1587
[3] 2095



This day in blog history:

Blog # Date Title Tags
363 23/05/2011 Apology Mobile phone
584 23/05/2013 Doctorate on hold DBA
857 23/05/2015 Venice log 4 - Waiting Holiday, Venice, Italy
1223 23/05/2019 Arriving in Athens (Greece 7) Holiday, Athens, Greece
1224 23/05/2019 Athens hop-on hop-off (Greece 8) Holiday, Athens, Greece

Sunday, May 17, 2026

Jasmine Myra - Where light settles

Two and a half months ago, I wroteJasmine Myra has recorded a new album that will be released in a few months' time (15 May 2026)! Over the past 12 months, there has been silence from her camp and I seriously wondered whether she was continuing with music. As I expected, there was a letter in my mailbox on May 15 giving me access to her new album, "Where light settles", so that I could download it in mp3 format.

I put the songs on continous play via the computer and have been listening to them as I work and read. And ... I don't know what to write. On a visceral level, I don't enjoy listening to this as much as I did the earlier work. I've been trying to figure out what the problem is, and I think that it's because the disc is less of a group performance this time. Drums, for example, are rarely heard. There also don't seem to be tunes that can be recognised as such but rather a collection of notes.

There is much less guiter and fewer harp arpeggios; the piano takes an even more dominant role that it had in the past (eg the opener, 'Opening' seems to be solo piano). There is more flute than bass clarinet. 

I think that my conclusion has to be: if these were the first tunes that I heard from Jasmine Myra then I wouldn't have been so enthusiastic about her work as I was when I first heard her.

Strangely, 'the new piece that does not as yet have a name but was influenced by Kenny Wheeler' that was played in Zurich, October 20242 does not appear here.

Internal links
[1] 2083
[2] 1876



This day in blog history:

Blog #Date TitleTags
85017/05/2015Florence log 3 - Take it easyHoliday, Florence, Italy
121717/05/2019Arriving at Andros (Greece 1)Holiday, Andros, Greece
131817/05/2020HeatwaveIsrael, Weather
150217/05/2022Yesterday's skyWeather
176117/05/2024In silenceSong writing
193717/05/2025Recording "Maeve's song" - production notesHome recording

Friday, May 08, 2026

Horizontal scolling

I haven't blogged much recently, primarily because there hasn't been much to blog about, but also because quite often I get struck by a mysterious malaise that hits at around 2 pm and only dissapates in the evening. I had a gastroscopy test at the beginning of the week whose conclusions were unclear; I don't have anything seriously wrong, but still. On the topic of health, I can report that since starting the new prophylactic medicine1 for migraines, I have been mercifully free of headaches, but there have been other side effects, such as adding 3 kg to my weight! And now for today's topic: horizontal scrolling.

In the OP's management program, there is a very simple form that has exactly one visible component, a TDBGrid. The grid's datasource is a query that has three fields: a date, a subject and a hidden id field. The subject can be very long and so it can be wider than the width of the form. Both the form and the grid have their bidimode set to biRightToLeft, as it should be for a Hebrew form. When one double clicks on the grid in order to open a form that is dependent on the hidden id field, the grid scrolls horizontally all the way to the left, thus effectively hiding the date field. A user complained that she had to scroll all the way to the right in order to overcome this.

I admit that I've seen this problem before but haven't cared enough to fix it. I also didn't know how to repair it. I assume that the solution would be some message that is sent to the grid to make it scroll back to the right. According to CoPilot, When a TDBGrid is in Right‑To‑Left mode: The visual left edge is actually the logical right edge. The scrollbar is reversed. When the grid receives focus again (after your double‑click opens the EditTask form), Windows sends a WM_HSCROLL message. The default handler scrolls the grid to the logical left, which in RTL mode is the visual right. But Delphi’s RTL support is partial, and the grid ends up scrolling to the visual left instead — exactly the opposite of what you want. So after returning from the EditTask form, the grid scrolls to the wrong side.

The fix seems to be to send the WM_HSROLL message to the grid (as I assumed): DBGrid1.Perform (WM_HSCROLL, SB_RIGHT, 0). But this code actually sends the cursor to the left of the grid (as I see it), whereas I want it to go to the right. So the real fix is DBGrid1.Perform (WM_HSCROLL, SB_LEFT, 0). And this does work.

Internal links
[1] 2095



This day in blog history:

Blog #Date TitleTags
7208/05/2007(Welcome to the) Hotel CaliforniaVan der Graaf Generator, Randy Newman, Jackson Browne, CSN, Barney Hoskyns
13008/05/2008Amsterdam diaryProgramming, Holiday, Amsterdam
35708/05/2011More facts your mother never told you about Word automationProgramming, Office automation
58108/05/2013Analysing my sleepCPAP, Gadgets
70408/05/2014Doctoring, researching, samplingDBA, Kindle
150008/05/20221500 blogsMeta-blogging
175708/05/2024Milano: the final dayComputers, Holiday, Italy, Milan

Saturday, May 02, 2026

Chamber music concert

I mentioned in a rather off the cuff manner a few months ago that 'there was supposed to be a chamber concert taking place in the kibbutz in another few hours' but that it was postponed because war with Iran had started that day. Finally, that chamber concert took place today and some of it was wonderful. 

The concert started with a short explanation about the harp as an instrument; this one had been built in the 1840s. The strings of a harp are tuned to a diatonic major scale, begging the question of how sharps and flats are played. It turns out that there are seven pedals at the bottom of the harp, where each pedal has three positions - flat, natural and sharp. This allows all the notes to be played, although sometimes enharmonics have to be employed, eg substituing F# for Gb. I know that Debussy wrote 'La fille aux cheveux de lin' (the girl with the flaxen hair) in the key of Gb which has six flats, so this must be a rather challenging piece to play.

The first piece of music to be played was Gabriel Fauré's 'Sicilienne' (Op. 78); the version that I am familiar with is played by cello and piano. There didn't seem to be much difference to the version played here by violin and harp, but this is always a good solid piece of music.

Next up was a real surprise as it wasn't in the pieces listed in the 'advert' for the concert - Debussy's 'Clair de lune' (the third part of the Suite Bergamasque). I wonder how the harp part was written as the music is notated in Db major with five flats. Surely it would be easier for both instruments simply to transpose the music up a semitone to D major - this would be a good key for the violin as well as two open strings, the D and A, are in this key. This was pure divine magic.

I have a memory of my mother saying that 'Clair de lune' was her favourite piece of music. Of course, I can't check with her as she passed away 24 years ago, and now it seems an odd statement for her to make as I don't have any recollection of her ever passing comment about a piece of music. I can't imagine any context in which she would have made this statement, either. But it is still a beautiful piece of music and the harp makes it more celestial than the piano does.

The other pieces on the set list were not familiar and I didn't enjoy them as much: a piece by Tchaikovsky that I can't name (a section from a violin concerto), Rumanian dances by Bartok, 'Fantasy for violin and harp' by Saint Saens (naturally I enjoyed this more). The final piece was probably part of 'Rapsodie espagnole' by Ravel (I didn't know that he was of Basque origin; I've always considered him to be French). I'm sorry to be so vague on the titles but I don't know the pieces and I'm having to transliteate their original names that were transliterated into Hebrew, so it's hard to be accurate.

The concert took place in a small building that one member turned into an art gallery. I was sitting in the second row on the left (I can recognise the bald patch on my head if I enlarge the picture) so of course the instruments were fairly loud, but they also had a large dynamic range as befitting top professional players.

Internal links
[1] 2083



This day in blog history:

Blog #Date TitleTags
17102/05/2009Heron - River of fortuneHeron
121302/05/2019DietHealth, Anaemia, Diet
175102/05/2024Menaggio in the rainHoliday, Italy, Varenna
193202/05/2025Maeve's songSong writing, Police procedurals

Monday, April 13, 2026

Batch inserts

Yesterday I wrote how it took 3 hours and 13 minutes to migrate a table with slightly over 2M records. I then tried my hand at the 'times' table; I saw that this table contained slightly more than 14 million records and so the migration should take around 21 hours - which it did. At least the program didn't crash. Obviously I had to find a better method - and I did: batch inserts. 

Basically, an array of 2048 records is prepared and then is inserted at one go. This saves multiple commits thus saving time. A 'commit'  permanently saves all changes made during a transaction, making them visible to other users and ensuring data integrity. Naturally this takes a certain amount of time - even if it's a few milliseconds, that adds up when it has to be done 14M times. My batch code needed to do only about 6,900 commits that should save a great deal of time.

I wasn't prepared for how fast migrating a table of 14M would be: four minutes!! That's 315 times faster than the naive method of copying row by row.

The batch inserts were possible in this database because the three large tables are composed solely of integers and there's no need to faff around with codepage conversions.

Here's the code

const batchsize = 2048; procedure Tq400IntMigrate.Button1Click(Sender: TObject); var i, j, k, fieldcount, position: integer; tablename, s: string; begin edit1.Text:= timetostr (time); button1.enabled:= false; for i:= 0 to componentcount - 1 do if components[i] is TCheckBox then if tCheckBox (components[i]).checked then begin tablename:= uppercase (tCheckBox (components[i]).caption); qCount.sql[1]:= tablename; qCount.open; pb.max:= qCount.fields[0].asinteger div batchsize; position:= 0; qDelete.SQL[1]:= tablename; qDelete.Connection:= newcon; qDelete.ExecSQL(); sleep (5000); qBase.sql[1]:= tablename; qBase.open; fieldcount:= qBase.fields.count - 1; s:= 'select '; for j := 0 to fieldcount - 1 do s:= s + qbase.fields[j].fieldname + ', '; s:= s + qBase.fields[fieldcount].fieldname + ' from ' + tablename; SrcQuery.sql.text:= s; srcQuery.open; s:= 'insert into ' + tablename + ' values ('; for j := 0 to fieldcount - 1 do s:= s + ':p' + inttostr (j) + ', '; s:= s + ':p' + inttostr (fieldcount) + ')'; dstquery.sql.text:= s; dstQuery.params.ArraySize:= batchsize; dstQuery.prepare; k:= 0; while not srcquery.eof do begin for j := 0 to fieldcount do case srcquery.fields[j].datatype of ftInteger: dstquery.params[j].asintegers[k]:= srcQuery.fields[j].asinteger; ftLargeInt: dstquery.params[j].aslargeints[k]:= srcQuery.fields[j].asinteger; else dstquery.params[j].asintegers[k]:= srcQuery.fields[j].asinteger; end; inc (k); if k = batchsize then begin dstquery.execute (batchsize); dstquery.connection.Commit; k:= 0; inc (position); pb.position:= position end; srcquery.next end; if k > 0 then begin dstquery.execute (k); dstquery.connection.Commit; end; end; edit2.Text:= timetostr (time); end;

Internal links
[1] 2104



This day in blog history:

Blog #Date TitleTags
34913/04/2011Advanced SQL for me - NULLIFProgramming, SQL
69613/04/2014Fifteen minute mealsCooking
82713/04/2015Vinyl log 3 - 13 AprilDCI Banks, Richard Thompson, Vinyl log
102113/04/2017April thesis updateDBA
160313/04/2023Rain, rain, rainWeather
174213/04/2024Jasmine Myra - KnowingnessJasmine Myra

Sunday, April 12, 2026

Wait states

I migrated another database to unicode over the weekend. Updating the migrator was fairly straight-forward, although there was one problematic table with something like 35,000 that was defined as WIN1251 (Cyrillic) although the characters were actually encoded in WIN1255 (Hebrew). That table took some time to define its migration route. Although this database has fewer tables than the first database that I converted and most of those tables contain only numbers with much less text, it took much longer to migrate the database - because some of the tables are huge (relatively speaking). There are a few tables with over two million rows and one with over ten million rows. 

Let us say that I had problems migrating those tables because of their size. I started the migration program yesterday evening only to discover that it had crashed whilst handling one of those humungous tables. I restarted the program from the table where it had crashed, but I could see that soon it too would crash. So what could I do?

I thought that the crashing might be due to the migration program overwhelming the database manager who simply could not keep up with the pace at which records were being entered. 30 years ago, this would be called 'adding wait states': a wait state is a deliberate, one-or-more clock cycle delay introduced by a processor to synchronize with slower external components, such as RAM or I/O devices. It prevents the CPU from processing data before it is ready, ensuring data integrity at the cost of overall system performance (thank you Chrome AI). 

The first thing that the migrator does for each table is delete any data that may exist in the table; I added the command 'sleep (15000)' after the deletion to allow the data to be deleted; this command stops the migrator for 15 seconds. I then added a command that there would be 10 second breaks after each 2048 records have been read. This was initially 15 seconds and 1024 records, but I could see that this would be too slow. For one table, with just over 2 million records with the sleep time was 10 seconds every 2048 records; it took 3 hours and 13 minutes to migrate the table.

I'm now migrating the really large table and don't expect it to finish within the next few hours - but I do expect it to complete.



This day in blog history:

Blog #Date TitleTags
82612/04/2015How not to display data in graphsStatistics
112112/04/2018Apology to Israel RailwaysTrains
160212/04/2023More bells and whistles for the 'Blog' programProgramming, Delphi, Blog manager program
174112/04/2024Update on our spring performanceMusical group
192112/04/2025Passover begins tonightJewish holidays, Song writing

Tuesday, April 07, 2026

The 'fx pedal to end all pedals' has ended its career

 The musical group had a knock-about session last night, playing anything that came into our collective head (eg 'Hotel California', 'Forever young' (Alphaville) and some Israeli songs - almost nothing that I have played before). Before we started, I checked out my pedal board and the fx pedal. I wrote 1 two months ago that the 'fx pedal to end all pedals'2 issues a fair amount of noise so in order to combat this, I set the noise gate to a level that let loud guitar through but not hiss. This caused the guitar to sound rather 'chunky' and lacking dynamics. Thinking about this on the way home, I realised that all the presets that I defined start with compression; maybe it would be better to create some presets with no compression and see what these sound like.

Before setting off for the rehearsal, I connected my phone to the pedal via bluetooth (and no small amount of bother) and attempted to remove the compression from all the settings. I think that I was partially successful in this. Despite my efforts, once I started playing, the sound from the amplifier was very weak. Exasperated, I disconnected the fx pedal from the system and suddenly my guitar volume increased ten-fold. I'll have to remove the pedal from the board and restore those that I previously removed.

On a completely different topic: yesterday was quite warm but this morning, when I was taking the dog for her morning walk, it started raining. Now that's not such an unusual event, but what makes it stand out is that the barometer in my head didn't give me a migraine. I did have an odd stomach ache in the evening, so this could be my body's new way of reacting, but it could also be due to the odd stomach rumblings from which I suffer now and then. So it looks like the new prophylactic pills3 that I have (that are meant for epileptics) are working.

Internal links
[1] 2074
[2] 2072
[3] 2095



This day in blog history:

Blog #Date TitleTags
56607/04/2013A new technique in Word AutomationProgramming, Office automation, HTML
82207/04/2015I've always kept a unicornSandy Denny, Fotheringay
111907/04/2018Season of the kumquatPersonal
130607/04/2020Statistical methods for EpidemiologistsStatistics, Covid-19, Non-fiction books

Sunday, April 05, 2026

Migration completed; now the debugging begins

At 5pm on Thursday afternoon, I completed the migration of the OP's management program with 354 units from ANSI Hebrew and dbExpress components to Unicode and FireDAC. When I write "completed", I mean that I had gone over every form and unit and replaced the dbExpress components with those of FireDAC. I also had briefly tested each form, but there was no guarantee that the program was free of bugs - in fact, I was fairly sure that the units that were converted first probably would not work correctly.

But before that, there was a topic that I had purposely not worked on, leaving it for the end. Almost all the forms that add data to the database have an autoincrement primary key; this is achieved by having a generator (something that returns a sequence of numbers, such as 1, 2, 3, ... 2001, 2002, etc) and a trigger that gets the next value from a generator and inserts it where needed. I didn't want functional generators when I was populating the new database from the old, but now that the translation had completed, I did need the generators and triggers for testing purposes. 

What I really needed was to drop all the generators and triggers before transferring any data, then to recreate them after all the data had been transferred. CoPilot got the dropping code partially correct - it would work if there was a trigger but wouldn't if there was no trigger. Eventually CP developed some complicated SQL code for a conditional delete. This also had to be done in the correct order: first delete the trigger then the generator; this is because the trigger refers to the generator. Recreating the generators and triggers was easy, at least when done in the correct order. Then the generators had to be seeded with their new starting value. Originally I wrote a small query that would return the maximum value in the key field and used this, but then I noticed that the migrator calculates how many rows are in a table (for a progress bar) so I used this - and shortly discovered that the number of rows is not necessarily the highest value of the key; there might have been deletions from the table. Eventually that was fixed and I migrated the database once more.

On Saturday morning, I started working through the program and found some simple problems to fix, for example queries that weren't attached to the database connection. I found more queries whose fields needed to be redefined, and I found some that were wrong because the columns to which they were connected were not defined correctly. This required a fix to the database and remigration of a single table. 

But there were some significant problems each of which took a few hours to fix. In what is probably the entire program's main form, the 'restore grid widths' routine wasn't working, although in fact, the correct values were returned but the grid 'ignored' them. The solution was to update the grid when all screen painting had finished, and so I added an OnPaint handler that sent a message to another procedure that would load the grid widths. This worked.

Another familiar problem occurred with a query called qSentReports: when certain reports are run, their HTML output is stored in a table so they can be retrieved at any stage. I had had problems when saving new reports in the table then restoring, so I assumed that retrieving reports that had been created in the previous version could be restored in a similar manner. But this was not so. According to CP, I was dealing with double or even triple encoding, involving WIN1255, WIN1252, UTF-16 and UTF-8. Then it struck me that the original data was already in UTF8 format, so the migrator shouldn't encode it and my code shouldn't decode it. After this epiphany, I once again transferred the data for this one table and finally it displayed correctly.

I am sure that there are further traps awaiting me, but I suspect that they will be minor. Now I don't know what to do with myself and all the free time that has suddenly opened up. ðŸ˜‰



This day in blog history:

Blog #Date TitleTags
24005/04/2010HolidayCooking
34605/04/2011Firebird fixed!Computers, Firebird
69205/04/2014PneumoniaHealth, Nick Drake
82105/04/2015Vinyl log 1 - 5 AprilVinyl log
93705/04/2016Sorrento shopping (2016/2)Holiday, Sorrento, Italy
111805/04/2018The sense of an ending (2)Films, Literature
120705/04/2019Excellent music blogBeatles, Song writing
159705/04/2023Passover night, 2023Jewish holidays, Kibbutz
192005/04/2025Slow cooked leg of lambCooking, Slow cooker

Thursday, April 02, 2026

2,100 blogs

Blog #2000 was written on 14/09/25, so that's 6.5 months for 100 blogs, or 15.8 blogs per month. Here is the histogram of blogs per month. The previous 100 blogs were written at an average pace of 14.3 blogs per month so I'm writing more.


I have to admit that I am surprised that 10/25 was such a fruitful month, although looking at what was written that month, I can understand. This was the beginning of the Prolog saga, a topic that would dominate the blog for the next few months - until a different programming project, the migration of a database and program to Unicode, began. Here are the blogs ordered by topic

Position Tag Count Previous position All time position
1 Programming 38 7 1
2 CoPilot 21 - 45
3 Prolog 21 - 39
4 Delphi 13 10 6
5 Personal 13 9 3
6 FireDAC 9 - 102
7 Unicode 8 - 50
8 Obituary 7 12 8
9 D12CE 6 - 142
10 Health 6 4 5
11 Israel 6 8 7
12 Computers 5 18 13
13 Films 5 - 18
14 Grandfather 4 - 37
15 Police procedurals 4 21 21
16 CPAP 3 - 23
17 Guitars 3 19 22
18 Musical group 3 5 27
19 Nick Drake 3 - 91

Of course, the period covered by these 100 blogs do not contain a holiday, so that's two topics off the board immediately. But it does seem that every six/seven months, my interests completely change. Here is the frequency histogram for the past 100 blogs.



Last night was the first night of Passover, and due to the security situation, we are back to the lock-down format1 from the Covid-19 days. At least this time our daughter and grandchildren joined us.

Internal links:
[1] 1307



This day in blog history:

Blog #Date TitleTags
12402/04/2008ERPProgramming, ERP, Maccabi Tel Aviv, Meta-blogging
82002/04/2015Introducing the vinyl log Vinyl log
111702/04/2018DBA updateDBA

Wednesday, April 01, 2026

Overconfident AI gets it wrong again

I wrote1 a few days ago: I would also like to define metadata for the database. For example, if a report uses the field 'name' from the table 'customers' then automatically that field should have the title 'customer name' (in Hebrew) Similarly, 'surname' and 'forename' from table 'people' or 'name' from table 'therapists'. The fact that I want the title in Hebrew is incidental; even in English, the default name for customers.name is 'name', not 'customer name'. I put this to CoPilot who replied that this would be very easy to do: it requires a dictionary that translates between table names and Hebrew titles, and that the source for the dictionary would be a property of each field called 'origin'. The origin propery of a field containing a customer name would be CUSTOMERS.NAME.

I left this idea for a few days while I concentrated on list boxes, but yesterday I returned to continue work on this idea. I linked the 'find dictionary entry' procedure to a simple report and saw ... that it didn't work. The origin of a field CUSTOMERS.NAME was simply NAME and of course I have to distinguish between customer name, therapist name and activities.name, etc. CoPilot said that the table name didn't appear because the query was very simple and didn't invoke a join. So I looked at a more complicated query and saw that the origin property was empty for half of the fields! Only fields from the base table (ie the table after the keyword FROM) had origins, whereas the rest didn't.

OK, said CoPilot, you need the OriginTabName and OriginColName properties. "These do exist and will compile." Except they don't exist. After several rounds of CoPilot offering names of properties that sound plausible but don't exist, I told CoPilot that we were getting nowhere. CP agreed, saying that FireDAC doesn't expose sufficient metadata in order to provide a solution for what I wanted. Thank you very much. It wouldn't hurt to say once in a while that "I got it wrong".

In the end, I suggested and implemented a much simpler - and unfortunately, less automatic - solution: I created a stringlist and populated it with the Hebrew translations of 'customer name', 'contact name', 'person surname', etc. Each value has a specific number attached to it which is simply the offset within the stringlist: stringlist[1] = 'customer name', etc. In the FDQueries and FDMemTables in my code, I assign one of these values to a field's tag propery and then do the lookup on this property. In the extremely complicated form for sending an email, upon which I worked, at one stage it is necessary to display a list of therapists. Instead of having to title each field manually, I simply marked the tags as 56 and 58 and got the displaylabels that I wanted.

In conclusion: there are some things that CoPilot is good at, like seeing that a datasource was not enabled2, or for building an ancestral dual list box dialog3. But for more creative solutions, CP is not particularly good and is even frequently wrong. And it still maintains that "This is reliable, simple, and works with all your existing forms". Yeah, right (the one time that two positives make a negative).

I've been so wrapped up in all this chat coding for the last few days that I didn't notice that this is blog #2100! The next blog will contain the traditional look at the previous 100 blogs.

Internal links
[1] 2097
[2] 2094
[3] 2099



This day in blog history:

Blog #Date TitleTags
138401/04/2021You and your action research projectDBA
191801/04/2025Is this me or a double?Personal

Tuesday, March 31, 2026

More about dual list boxes

After a minimal amount of research, I discovered that the dual listbox is regarded as a very good solution when one wants to select and organise options. I did some work with CoPilot on the subject last night; most of the time went on creating an ancestral form for the dual listbox dialog and a small amount of time working on a form that inherits from the ancestor. This morning I spent some time improving the visual aspects of the form and fixing a few bugs that had crept in (mainly misnaming errors).

Above is pictured an example of the form when it is populated with data. Just to make things slightly more difficult, it is of course drawn right-to-left. Until now, if I was feeling adventurous, I would place a bevel around a listbox or grid, slightly improving the appearance, but it struck me that it would be better to use a coloured panel and place the listbox on top of the panel - that's what gives the blue frame surrounding both list boxes. 

The form that inherits from the ancestor now contains about twenty lines of text - and that's all! The only things that differ between various descendant forms are their captions and the specific queries for loading the list boxes and saving the changes.

type TAddXtraRateActs = class(TDualListBox) private public procedure Execute (anxtra: longint; const aname: string); end; implementation {$R *.dfm} uses managedm; Procedure TAddXtraRateActs.Execute (anxtra: longint; const aname: string); begin dm.ProgLog (178); LeftID:= anxtra; caption:= ' הוספת פעילויות לבונוס עבור ' + aname; qDistList.sql.text:= 'select activities.name, activities.id ' + 'from activities inner join xtrarateact ' + 'on activities.id = xtrarateact.act ' + 'where xtrarateact.xtra = :LeftID'; qSrchList.sql.text:= 'select activities.id, activities.name ' + 'from activities where not exists ' + '(select 1 from xtrarateact ' + 'where xtrarateact.act = activities.id ' + 'and xtrarateact.xtra = :LeftID)'; qInsert.sql.text:= 'insert into xtrarateact (xtra, act) ' + 'values (:LeftID, :RightID)'; qDelete.sql.text:= 'delete from xtrarateact where xtra = :LeftID ' + 'and act = :RightID'; Initialise; // load the lists only after there is valid SQL in the queries showmodal end;

That's it! Converting existing forms to this new format is a bit awkward but not difficult. It is important during the change-over to guard the sql statements from being lost, although I do have backups in the form of the original non-unicode program.



This day in blog history:

Blog #Date TitleTags
12331/03/2008Lots of things to doProgramming, Psychology, Van der Graaf Generator, Ian Rankin, Dog, DVD, Brian Viner, Management exams
34431/03/2011Intellectual stimulation and frustrationERP, MBA, HRM, Dan Ariely
46731/03/2012Sequencing "Darkness" / 2MIDI, Van der Graaf Generator, Home recording
81931/03/2015New mobile computerComputers

Monday, March 30, 2026

Updating the dual list box interface

Many moons ago, I wrote1 about an internal improvement to the 'dual list box dialog. This is a template that came with the original version of Delphi and has served us well over the years. 

Yesterday, whilst reading the 'vibe coding2' book, I began thinking of ways to improve the appearance of the program and not have it stuck in the early 2000s. The first thing that came to mind was the above dialog box: wouldn't it be easier if there were only one checklistbox on the form? The user either marks (or removes marks) in order to add or remove an item from the collection. It turns out that programming this dialog is far simpler than the old dialog, but that shouldn't be a factor in deciding which format to use.

I sent both pictures to the OP so that she could give her opinion. Originally she chose the dual list box version "because this is what I know and it is very clear which items have been selected". I replied "boring", to which she replied "go with the new format if it's easier". At the moment I'm not going to convert any more forms to this new format - I want to give her a chance to make a more considered choice.

Internal links
[1] 307
[2] 2097



This day in blog history:

Blog #Date TitleTags
102030/03/2017Mint chocolatePeppermint
120630/03/2019New songSong writing, Multi-track

Sunday, March 29, 2026

Chat coding

On and off, I'm reading a book entitled 'Vibe coding' by Gene Kim and Steve Yegge that tells about the joys of working with AI to enhance programmers' productivity. It turns out that I am using AI for what is called 'chat coding': I write about the problems that I'm having, and AI (in my case, CoPilot) offers suggestions for continuing. I don't like asking AI to write my code for me! Anyway, at the moment I'm migrating previously written code, so I try to change as little as possible.

Yesterday I saw both the best and the worst of chat coding. I'll explain the scenario first before I get into what happens. One screen in the management program displays for each therapist/worker how many hours were worked or meetings held by that person in the previous month. The data is displayed in an internal web browser control, where the contents are in hand-written HTML; this means that I wrote queries then took the values and enclosed their values with my own HTML. This code was written at least 10 years ago when we didn't have chat coding. It works very well so there's nothing worth improving (so I think).

Should the person running the program so desire, the monthly report for a therapist can be sent via email; this basically means taking the already written HTML code and enclosing it within an email. I wrote about this years ago. Not only that, the report is saved in the database so it can be retrieved at any time. A second screen displays a list of such saved reports within a given time period, and should one so desire, a report can be retrieved and shown in a third screen, which is simply a web browser.

All seemed to be fine until I noticed that the user reports that I had created and saved that day were appearing in the reports list without a subject (title). I then spent what seemed to be an hour chasing the problem with CP; it was frustrating because everything seemed to be ok, but it wasn't. Eventually I uploaded the screen's DFM file and CP saw immediately saw what the problem was: the field before the missing field was defined as a string field of length 20,000 characters when in fact it should be a blob. So I corrected the query and the parameter, and saved some more reports. These appeared with subject in the intermediate screen.

But when I tried to access the saved reports, I saw what is normally referred to as gibberish: Chinese characters flowed across the screen. Reports that had been created prior to yesterday (in fact, prior to the redefinition of the field as a blob) displayed correctly. CP decided that the problem was with the web browser component that is based on IE7, i.e. very old and not particularly compatible with unicode. So I replaced the web browser with the edge browser component that is the new standard component for displaying HTML ... and then discovered that the component itself did not appear on the form. Ah, said CP, you have to initialise the browser. No change. Ah, said CP, you have to wait for the browse to finish initialising before you can display your page. No change, the browser still does not appear. Ah, said CP, you need a specific dll that you probably have on your computer. Copy the file to your program's directory. No changed. Ah, said CP, download a new version from such and such a website and make sure that you have the correct version (32 bits or 64 bits). Even that didn't work and I'm not sure that I was even downloading what I needed.

Fortunately - if that is the correct word - we had an air raid alarm (two missiles fell not far away from us) so I could disconnect from the computer and think a little. When I returned, I told CP that we were returning to the old web browser component because this worked. I then discovered that the original text wasn't being saved in the blob field in unicode (I checked via the database manger) - it was being saved as ANSI - so I resurrected a routine from the database migrator1 and used it to save the text. This of course required that when the text is retrieved from the database, it also has to be converted. Finally the reports were being saved with subjects and could be shown correctly after retrieval from the database.

I then took the dog for a walk and thought about how I could turn the code that we had just written into a library routine. I was using the 'save' routine several times (and I suspect that I will need it again when I get to saving general emails) and it seemed excessive to write the same code over and over again, but it was also tightly coupled to a query. When I came back from the walk, I told this to CP who responded with a unit that included routines for saving and retrieving unicode blobs. A bit later, I required another similar routine that CP wrote which I added to the unit.

The book itself isn't too useful as it talks about tools and AI agents that I don't use and don't have access to. I am sure that they consider Delphi to be very old fashioned, but if it gets the work done then it's good. I want to quote two passages from the book.

When Gene first started vibe coding with Steve, Gene was convinced that the then-new OpenAI o1 model would be great at ffmpeg and could help him overlay captions onto video excerpts. That is to say, subtitles on YouTube clips. Two hours later, Gene ran around in circles, typing increasingly complex ffmpeg commands. The AI was more than wrong; It was confidently wrong. Thinking about that particular Sunday afternoon still causes Gene to clench his jaw. But he learned an important lesson on when to give up on using AI to solve certain types of problems. It was a crummy experience, but he learned from it because it was a crummy experience. You learn by doing.

Here are some other takeaways from this early vibe coding session: AIs are capable of handling small to medium tasks, including in less popular programming languages, and using fairly complex Unix command-line tools. You interact with AI as if it were a senior pair programmer who’s so distracted that they can make serious mistakes from time to time.

The book did inspire me to think of some tasks that I would like to look at after the migration has been finished. I would like to improve the visual aspect of the program: I am a person who thinks in terms of tables and not graphs, so the visual aspects aren't too important to me, but I would like to see how they can be improved. Another task is the problem of choosing multiple values for a parameter, i.e. instead of choosing one customer for a report, several customers can be chosen. I have this functionality but I want to see whether it can be improved. I have thought of one way already, and as this functionality is contained within one specific unit (but is used by many others), it would be quite easy to test.

I would also like to define metadata for the database. For example, if a report uses the field 'name' from the table 'customers' then automatically that field should have the title 'customer name' (in Hebrew) Similarly, 'surname' and 'forename' from table 'people' or 'name' from table 'therapists'. The fact that I want the title in Hebrew is incidental; even in English, the default name for customers.name is 'name', not 'customer name'.

Internal links
[1] 2075



This day in blog history:

Blog #Date TitleTags
16429/03/2009The big chillFilms
23929/03/2010Pesach over the yearsJewish holidays, Obituary, Habonim, David Lodge, France
34229/03/2011I haven't disappeared off the face of the EarthPeter Robinson, Van der Graaf Generator, Ian Rankin, Steig Larsson, BCC, Jo Nesbo
34329/03/2011The camino pilgrimageDavid Lodge
46629/03/2012Nobel prize winner visits MBAMBA
101929/03/2017The label number bugPriority tips